Quand et comment l'utiliser – Real Python

By | février 17, 2021

Cours Python en ligne

Programmation fonctionnelle est un paradigme de programmation dans lequel la principale méthode de calcul est l'évaluation des fonctions. Dans ce didacticiel, vous explorerez la programmation fonctionnelle en Python.

La programmation fonctionnelle joue généralement un rôle assez petit dans le code Python. Mais il est bon de le connaître. Au minimum, vous le rencontrerez probablement de temps en temps lors de la lecture de code écrit par d'autres. Vous pouvez même trouver des situations dans lesquelles il est avantageux d’utiliser les capacités de programmation fonctionnelle de Python dans votre propre code.

Dans ce didacticiel, vous apprendrez:

  • Qu'est-ce que programmation fonctionnelle le paradigme implique
  • Ce que ça veut dire de dire ça les fonctions sommes citoyens de première classe en Python
  • Comment définir fonctions anonymes avec le lambda mot-clé
  • Comment implémenter le code fonctionnel en utilisant carte(), filtre(), et réduire()

Qu'est-ce que la programmation fonctionnelle?

UNE fonction pure est une fonction dont la valeur de sortie découle uniquement de ses valeurs d'entrée, sans aucun effet secondaire observable. Dans programmation fonctionnelle, un programme consiste entièrement en l'évaluation de fonctions pures. Le calcul procède par des appels de fonction imbriqués ou composés, sans changement d'état ou de données mutables.

Le paradigme fonctionnel est populaire car il offre plusieurs avantages par rapport aux autres paradigmes de programmation. Le code fonctionnel est:

  • Haut niveau: Vous décrivez le résultat souhaité plutôt que de spécifier explicitement les étapes nécessaires pour y parvenir. Les déclarations simples ont tendance à être concises, mais ont beaucoup de punch.
  • Transparent: Le comportement d'une fonction pure ne dépend que de ses entrées et sorties, sans valeurs intermédiaires. Cela élimine la possibilité d'effets secondaires, ce qui facilite le débogage.
  • Parallélisable: Les routines qui ne provoquent pas d'effets secondaires peuvent plus facilement fonctionner en parallèle les unes avec les autres.

De nombreux langages de programmation prennent en charge un certain degré de programmation fonctionnelle. Dans certains langages, pratiquement tout le code suit le paradigme fonctionnel. Haskell en est un exemple. Python, en revanche, prend en charge la programmation fonctionnelle mais contient également des fonctionnalités d'autres modèles de programmation.

S'il est vrai qu'une description approfondie de la programmation fonctionnelle est quelque peu complexe, le but ici n'est pas de présenter une définition rigoureuse mais de vous montrer ce que vous pouvez faire au moyen de la programmation fonctionnelle en Python.

Dans quelle mesure Python prend-il en charge la programmation fonctionnelle?

Pour prendre en charge la programmation fonctionnelle, il est utile qu’une fonction d’un langage de programmation donné ait deux capacités:

  1. Prendre une autre fonction comme argument
  2. Pour renvoyer une autre fonction à son appelant

Python joue bien à ces deux égards. Comme vous l’avez appris précédemment dans cette série, tout dans un programme Python est un objet. Tous les objets en Python ont une stature plus ou moins égale et les fonctions ne font pas exception.

En Python, les fonctions sont citoyens de première classe. Cela signifie que les fonctions ont les mêmes caractéristiques que les valeurs telles que les chaînes et les nombres. Tout ce que vous vous attendez à pouvoir faire avec une chaîne ou un nombre, vous pouvez également le faire avec une fonction.

Par exemple, vous pouvez affecter une fonction à une variable. Vous pouvez ensuite utiliser cette variable de la même manière que vous utiliseriez la fonction elle-même:

>>>

    1>>> def func():
    2...     impression("Je suis la fonction func ()!")
    3...
    4
    5>>> func()
    6Je suis la fonction func ()!
    7
    8>>> un autre nom = func
    9>>> un autre nom()
dixJe suis la fonction func ()!

La tâche autre_nom = func à la ligne 8 crée une nouvelle référence à func () nommé un autre nom. Vous pouvez alors appeler la fonction par l'un ou l'autre nom, func ou un autre nom, comme indiqué aux lignes 5 et 9.

Vous pouvez afficher une fonction sur la console avec impression(), incluez-le en tant qu'élément dans un objet de données composite comme une liste, ou même utilisez-le comme clé de dictionnaire:

>>>

>>> def func():
...     impression("Je suis la fonction func ()!")
...

>>> impression("chat", func, 42)
chat  42

>>> objets = [[[["chat", func, 42]
>>> objets[[[[1]

>>> objets[[[[1]()
Je suis la fonction func ()!

>>>  = "chat": 1, func: 2, 42: 3
>>> [[[[func]
2

Dans cet exemple, func () apparaît dans tous les mêmes contextes que les valeurs "chat" et 42, et l'interprète le gère très bien.

Pour les besoins actuels, ce qui compte, c'est que les fonctions en Python satisfassent aux deux critères bénéfiques pour la programmation fonctionnelle énumérés ci-dessus. Vous pouvez passer une fonction à une autre fonction en tant qu'argument:

>>>

    1>>> def intérieur():
    2...     impression("Je suis une fonction interne ()!")
    3...
    4
    5>>> def extérieur(fonction):
    6...     fonction()
    7...
    8
    9>>> extérieur(intérieur)
dixJe suis la fonction intérieure ()!

Voici ce qui se passe dans l'exemple ci-dessus:

  • L'appel sur la ligne 9 passe intérieur() comme argument pour extérieur().
  • Dans extérieur(), Python lie intérieur() au paramètre de fonction fonction.
  • extérieur() peut alors appeler intérieur() directement via fonction.

Ceci est connu comme composition de fonction.

Lorsque vous passez une fonction à une autre fonction, la fonction transmise est parfois appelée rappeler parce qu'un rappeler à la fonction interne peut modifier le comportement de la fonction externe.

Un bon exemple de ceci est la fonction Python trié (). Normalement, si vous transmettez une liste de valeurs de chaîne à trié (), puis il les trie dans l'ordre lexical:

>>>

>>> animaux = [[[["furet", "campagnol", "chien", "gecko"]
>>> trié(animaux)
['dog', 'ferret', 'gecko', 'vole']

Pourtant, trié () prend une option clé argument qui spécifie une fonction de rappel pouvant servir de clé de tri. Ainsi, par exemple, vous pouvez trier par longueur de chaîne à la place:

>>>

>>> animaux = [[[["furet", "campagnol", "chien", "gecko"]
>>> trié(animaux, clé=len)
['dog', 'vole', 'gecko', 'ferret']

trié () peut également prendre un argument facultatif qui spécifie le tri dans l'ordre inverse. Mais vous pouvez gérer la même chose en définissant votre propre fonction de rappel qui inverse le sens de len ():

>>>

>>> animaux = [[[["furet", "campagnol", "chien", "gecko"]
>>> trié(animaux, clé=len, sens inverse=Vrai)
['ferret', 'gecko', 'vole', 'dog']

>>> def reverse_len(s):
...     revenir -len(s)
...
>>> trié(animaux, clé=reverse_len)
['ferret', 'gecko', 'vole', 'dog']

Vous pouvez vérifier comment utiliser trié () et Trier() en Python pour plus d'informations sur le tri des données en Python.

Tout comme vous pouvez passer une fonction à une autre fonction en tant qu'argument, une fonction peut également spécifier une autre fonction comme valeur de retour:

>>>

    1>>> def extérieur():
    2...     def intérieur():
    3...             impression("Je suis une fonction interne ()!")
    4...
    5...     # La fonction Outside () renvoie la fonction inner ()
    6...     revenir intérieur
    7...
    8
    9>>> fonction = extérieur()
dix>>> fonction
11<fonction externe..inner à 0x7f18bc85faf0>
12>>> fonction()
13Je suis la fonction intérieure ()!
14
15>>> extérieur() ()
16Je suis la fonction intérieure ()!

Voici ce qui se passe dans cet exemple:

  • Lignes 2 à 3: extérieur() définit une fonction locale intérieur().
  • Ligne 6: extérieur() passe intérieur() retour comme valeur de retour.
  • Ligne 9: La valeur de retour de extérieur() est affecté à la variable fonction.

Suite à cela, vous pouvez appeler intérieur() indirectement à travers fonction, comme indiqué à la ligne 12. Vous pouvez également l'appeler indirectement en utilisant la valeur de retour de extérieur() sans affectation intermédiaire, comme à la ligne 15.

Comme vous pouvez le voir, Python a mis en place les éléments nécessaires pour prendre en charge la programmation fonctionnelle correctement. Avant de vous lancer dans le code fonctionnel, cependant, il y a un autre concept qui vous sera utile à explorer: le lambda expression.

Définition d'une fonction anonyme avec lambda

La programmation fonctionnelle consiste à appeler des fonctions et à les transmettre, elle implique donc naturellement de définir de nombreuses fonctions. Vous pouvez toujours définir une fonction de la manière habituelle, en utilisant le def mot-clé comme vous l'avez vu dans les didacticiels précédents de cette série.

Parfois, cependant, il est pratique de pouvoir définir un fonction anonyme à la volée, sans avoir à lui donner un nom. En Python, vous pouvez le faire avec un lambda expression.

La syntaxe d'un lambda l'expression est la suivante:

lambda <liste_paramètres>: <expression>

Le tableau suivant résume les parties d'un lambda expression:

Composant Sens
lambda Le mot-clé qui introduit un lambda expression
Une liste facultative de noms de paramètres séparés par des virgules
: Ponctuation qui sépare de
Une expression impliquant généralement les noms dans

La valeur d'un lambda expression est une fonction appelable, tout comme une fonction définie avec le def mot-clé. Il prend des arguments, comme spécifié par et renvoie une valeur, comme indiqué par .

Voici un premier exemple rapide:

>>>

    1>>> lambda s: s[::[::[::[::-1]
    2<fonction  à 0x7fef8b452e18>
    3
    4>>> appelable(lambda s: s[::[::[::[::-1])
    5Vrai

L'énoncé de la ligne 1 est juste le lambda expression par elle-même. Sur la ligne 2, Python affiche la valeur de l'expression, que vous pouvez voir est une fonction.

La fonction Python intégrée appelable () Retour Vrai si l'argument qui lui est passé semble être appelable et Faux autrement. Les lignes 4 et 5 montrent que la valeur renvoyée par le lambda expression est en fait appelable, comme une fonction devrait l'être.

Dans ce cas, la liste de paramètres se compose du paramètre unique s. L'expression suivante s[::-1] est une syntaxe de découpage qui renvoie les caractères dans s dans le sens inverse. Donc ça lambda expression définit une fonction temporaire et sans nom qui prend un argument de chaîne et renvoie la chaîne d'argument avec les caractères inversés.

L'objet créé par un lambda expression est un citoyen de première classe, tout comme une fonction standard ou tout autre objet en Python. Vous pouvez l'affecter à une variable puis appeler la fonction en utilisant ce nom:

>>>

>>> sens inverse = lambda s: s[::[::[::[::-1]
>>> sens inverse("Je suis une chaîne")
'gnirts a ma je'

Cela équivaut fonctionnellement – sans jeu de mots – à définir sens inverse() avec le def mot-clé:

>>>

    1>>> def sens inverse(s):
    2...     revenir s[::[::[::[::-1]
    3...
    4>>> sens inverse("Je suis une chaîne")
    5'gnirts a ma je'
    6
    7>>> sens inverse = lambda s: s[::[::[::[::-1]
    8>>> sens inverse("Je suis une chaîne")
    9'gnirts a ma je'

Les appels sur les lignes 4 et 8 ci-dessus se comportent de la même manière.

Cependant, il n’est pas nécessaire d’affecter une variable à un lambda expression avant de l'appeler. Vous pouvez également appeler la fonction définie par un lambda expression directement:

>>>

>>> (lambda s: s[::[::[::[::-1]) ("Je suis une chaîne")
'gnirts a ma je'

Voici un autre exemple:

>>>

>>> (lambda x1, x2, x3: (x1 + x2 + x3) / 3) (9, 6, 6)
7,0
>>> (lambda x1, x2, x3: (x1 + x2 + x3) / 3) (1,4, 1.1, 0,5)
1.0

Dans ce cas, les paramètres sont x1, x2, et x3, et l'expression est x1 + x2 + x3 / 3. C'est un anonyme lambda fonction pour calculer la moyenne de trois nombres.

Comme autre exemple, rappelez-vous ci-dessus lorsque vous avez défini un reverse_len () pour servir de fonction de rappel pour trié ():

>>>

>>> animaux = [[[["furet", "campagnol", "chien", "gecko"]

>>> def reverse_len(s):
...     revenir -len(s)
...
>>> trié(animaux, clé=reverse_len)
['ferret', 'gecko', 'vole', 'dog']

Vous pouvez utiliser un lambda fonctionnent ici aussi:

>>>

>>> animaux = [[[["furet", "campagnol", "chien", "gecko"]
>>> trié(animaux, clé=lambda s: -len(s))
['ferret', 'gecko', 'vole', 'dog']

UNE lambda expression aura généralement une liste de paramètres, mais ce n’est pas obligatoire. Vous pouvez définir un lambda fonction sans paramètres. La valeur de retour ne dépend alors d'aucun paramètre d'entrée:

>>>

>>> quarante_deux_producteurs = lambda: 42
>>> quarante_deux_producteurs()
42

Notez que vous ne pouvez définir que des fonctions assez rudimentaires avec lambda. La valeur de retour d'un lambda expression ne peut être qu’une seule expression. UNE lambda l'expression ne peut pas contenir des instructions telles que l'attribution ou revenir, il ne peut pas non plus contenir de structures de contrôle telles que pour, tandis que, si, autre, ou def.

Vous avez appris dans le didacticiel précédent sur la définition d'une fonction Python qu'une fonction définie avec def peut effectivement renvoyer plusieurs valeurs. Si un revenir L'instruction dans une fonction contient plusieurs valeurs séparées par des virgules, puis Python les emballe et les renvoie sous forme de tuple:

>>>

>>> def func(X):
...     revenir X, X ** 2, X ** 3
...
>>> func(3)
(3, 9, 27)

Cet emballage de tuple implicite ne fonctionne pas avec un anonyme lambda fonction:

>>>

>>> (lambda X: X, X ** 2, X ** 3) (3)
: 1: SyntaxWarning: l'objet 'tuple' n'est pas appelable; peut-être avez-vous manqué une virgule?
Traceback (dernier appel le plus récent):
  Déposer "", ligne 1, dans 
NameError: le nom 'x' n'est pas défini

Mais vous pouvez renvoyer un tuple à partir d'un lambda fonction. Il vous suffit de désigner explicitement le tuple avec des parenthèses. Vous pouvez également renvoyer une liste ou un dictionnaire à partir d'un lambda fonction:

>>>

>>> (lambda X: (X, X ** 2, X ** 3)) (3)
(3, 9, 27)
>>> (lambda X: [[[[X, X ** 2, X ** 3]) (3)
[3, 9, 27]
>>> (lambda X: 1: X, 2: X ** 2, 3: X ** 3) (3)
1: 3, 2: 9, 3: 27

UNE lambda expression a son propre espace de noms local, de sorte que les noms de paramètres ne sont pas en conflit avec des noms identiques dans l'espace de noms global. UNE lambda expression peut accéder aux variables de l’espace de noms global, mais ne peut pas les modifier.

Il y a une dernière bizarrerie à prendre en compte. Si vous trouvez un besoin d'inclure un lambda expression dans une chaîne littérale formatée (chaîne F), vous devrez la mettre entre parenthèses explicites:

>>>

>>> impression(F"--- lambda s:    s[::-1]    --- ")
  Déposer "", ligne 1
    (lambda s)
             ^
Erreur de syntaxe: f-string: syntaxe invalide

>>> impression(F"--- (lambda s: s[::[::[::[::-1])    --- ")
--- <fonction  à 0x7f97b775fa60> ---
>>> impression(F"--- (lambda s: s[::[::[::[::-1]) ('Je suis une chaîne')    --- ")
--- gnirts un ma je ---

Vous savez maintenant comment définir une fonction anonyme avec lambda. Pour en savoir plus sur lambda fonctions, consultez Comment utiliser les fonctions Python Lambda.

Ensuite, il est temps de se plonger dans la programmation fonctionnelle en Python. Vous verrez comment lambda Les fonctions sont particulièrement pratiques lors de l'écriture de code fonctionnel.

Python propose deux fonctions intégrées, carte() et filtre(), qui correspondent au paradigme de la programmation fonctionnelle. Un tiers, réduire(), ne fait plus partie du langage de base mais est toujours disponible à partir d'un module appelé functools. Chacune de ces trois fonctions prend une autre fonction comme l'un de ses arguments.

Application d'une fonction à un itérable avec carte()

La première fonction du dossier est carte(), qui est une fonction intégrée Python. Avec carte(), vous pouvez appliquer une fonction à chaque élément d'un itérable à son tour, et carte() renverra un itérateur qui donne les résultats. Cela peut permettre un code très concis car un carte() L'instruction peut souvent remplacer une boucle explicite.

Appel carte() Avec un seul itérable

La syntaxe pour appeler carte() sur un seul itérable ressemble à ceci:

carte(, ) retourne dans l'itérateur qui donne les résultats de l'application de la fonction à chaque élément de .

Voici un exemple. Supposons que vous ayez défini sens inverse(), une fonction qui prend un argument de chaîne et renvoie son inverse, en utilisant votre vieil ami le [::-1] mécanisme de tranchage de cordes:

>>>

>>> def sens inverse(s):
...     revenir s[::[::[::[::-1]
...
>>> sens inverse("Je suis une chaîne")
'gnirts a ma je'

Si vous avez une liste de chaînes, vous pouvez utiliser carte() postuler sens inverse() à chaque élément de la liste:

>>>

>>> animaux = [[[["chat", "chien", "hérisson", "gecko"]
>>> itérateur = carte(sens inverse, animaux)
>>> itérateur

Mais rappelles-toi, carte() ne renvoie pas de liste. Il renvoie un itérateur appelé a objet de carte. Pour obtenir les valeurs de l'itérateur, vous devez soit l'itérer soit utiliser liste():

>>>

>>> itérateur = carte(sens inverse, animaux)
>>> pour je dans itérateur:
...     impression(je)
...
tac
Dieu
gohegdeh
okceg

>>> itérateur = carte(sens inverse, animaux)
>>> liste(itérateur)
['tac', 'god', 'gohegdeh', 'okceg']

Itérer itérateur renvoie les éléments de la liste d'origine animaux, avec chaque chaîne inversée par sens inverse().

Dans cet exemple, sens inverse() est une fonction assez courte, dont vous pourriez bien ne pas avoir besoin en dehors de cette utilisation avec carte(). Plutôt que d'encombrer le code avec une fonction jetable, vous pouvez utiliser une fonction anonyme lambda fonction à la place:

>>>

>>> animaux = [[[["chat", "chien", "hérisson", "gecko"]
>>> itérateur = carte(lambda s: s[::[::[::[::-1], animaux)
>>> liste(itérateur)
['tac', 'god', 'gohegdeh', 'okceg']

>>> # Combiner tout cela en une seule ligne:
>>> liste(carte(lambda s: s[::[::[::[::-1], [[[["chat", "chien", "hérisson", "gecko"]))
['tac', 'god', 'gohegdeh', 'okceg']

Si l'itérable contient des éléments qui ne conviennent pas pour la fonction spécifiée, Python lève une exception:

>>>

>>> liste(carte(lambda s: s[::[::[::[::-1], [[[["chat", "chien", 3,14159, "gecko"]))
Traceback (dernier appel le plus récent):
  Déposer "", ligne 1, dans 
  
  
  
  Déposer "", ligne 1, dans 
Erreur-type: L'objet 'float' n'est pas en indice

Dans ce cas, le lambda La fonction attend un argument de chaîne, qu'elle essaie de découper. Le deuxième élément de la liste, 3,14159, est un flotter objet, qui ne peut pas être découpé. Donc un Erreur-type se produit.

Voici un exemple un peu plus réel: dans la section du didacticiel sur les méthodes de chaîne intégrées, vous avez rencontré str.join (), qui concatène les chaînes d'un itérable, séparées par la chaîne spécifiée:

>>>

>>> "+".rejoindre([[[["chat", "chien", "hérisson", "gecko"])
'chat + chien + hérisson + gecko'

Cela fonctionne bien si les objets de la liste sont des chaînes. S'ils ne le sont pas, alors str.join () soulève un Erreur-type exception:

>>>

>>> "+".rejoindre([[[[1, 2, 3, 4, 5])
Traceback (dernier appel le plus récent):
  Déposer "", ligne 1, dans 
Erreur-type: élément de séquence 0: instance de str attendue, int trouvé

Une façon d'y remédier est d'utiliser une boucle. Utilisant un pour boucle, vous pouvez créer une nouvelle liste contenant des représentations sous forme de chaîne des nombres de la liste d'origine. Ensuite, vous pouvez transmettre la nouvelle liste à .rejoindre():

>>>

>>> cordes = []
>>> pour je dans [[[[1, 2, 3, 4, 5]:
...     cordes.ajouter(str(je))
...
>>> cordes
['1', '2', '3', '4', '5']
>>> "+".rejoindre(cordes)
«1 + 2 + 3 + 4 + 5»

Cependant, parce que carte() applique une fonction à chaque objet d'une liste à son tour, il peut souvent éliminer le besoin d'une boucle explicite. Dans ce cas, vous pouvez utiliser carte() postuler str () aux objets de la liste avant de les joindre:

>>>

>>> "+".rejoindre(carte(str, [[[[1, 2, 3, 4, 5]))
«1 + 2 + 3 + 4 + 5»

carte (str, [1, 2, 3, 4, 5]) renvoie un itérateur qui donne la liste des objets chaîne ["1", "2", "3", "4", "5"], et vous pouvez ensuite transmettre avec succès cette liste à .rejoindre().

Même si carte() accomplit l'effet désiré dans l'exemple ci-dessus, il serait plus pythonique d'utiliser une compréhension de liste pour remplacer la boucle explicite dans un cas comme celui-ci.

Appel carte() Avec plusieurs itérables

Il existe une autre forme de carte() qui prend plus d'un argument itérable:

carte(<F>, <itérable>, <itérable>, ..., <itérableₙ>)

carte(, <itérable1>, <itérable2>, ..., <itérablen>) s'applique aux éléments de chaque <itérableje> en parallèle et renvoie un itérateur qui donne les résultats.

Le nombre de <itérableje> arguments spécifiés à carte() doit correspondre au nombre d'arguments qui attend. agit sur le premier élément de chaque <itérableje>, et ce résultat devient le premier élément généré par l'itérateur de retour. Puis agit sur le deuxième élément de chaque <itérableje>, et cela devient le deuxième élément produit, et ainsi de suite.

Un exemple devrait aider à clarifier:

>>>

>>> def F(une, b, c):
...     revenir une + b + c
...

>>> liste(carte(F, [[[[1, 2, 3], [[[[dix, 20, 30], [[[[100, 200, 300]))
[111, 222, 333]

Dans ce cas, F() prend trois arguments. En conséquence, il existe trois arguments itérables pour carte(): les listes [1, 2, 3], [10, 20, 30], et [100, 200, 300].

Le premier article retourné est le résultat de l'application F() au premier élément de chaque liste: f (1, 10, 100). Le deuxième article retourné est f (2, 20, 200), et le troisième est f (3, 30, 300), comme illustré dans le diagramme suivant:

Diagramme d'appel map () avec plusieurs itérables

La valeur de retour de carte() est un itérateur qui donne la liste [111, 222, 333].

Encore une fois dans ce cas, puisque F() est si court que vous pourriez facilement le remplacer par un lambda fonction à la place:

>>>

>>> liste(
...     carte(
...         (lambda une, b, c: une + b + c),
...         [[[[1, 2, 3],
...         [[[[dix, 20, 30],
...         [[[[100, 200, 300]
...     )
... )

Cet exemple utilise des parenthèses supplémentaires autour du lambda fonction et continuation de ligne implicite. Ni l'un ni l'autre n'est nécessaire, mais ils aident à rendre le code plus facile à lire.

Sélection d'éléments à partir d'un itérable avec filtre()

filtre() vous permet de sélectionner ou de filtrer les éléments d'un itérable en fonction de l'évaluation de la fonction donnée. Il s’appelle comme suit:

filtre(, ) applique la fonction à chaque élément de et renvoie un itérateur qui donne tous les éléments pour lesquels est la vérité. À l'inverse, il filtre tous les éléments pour lesquels est faux.

Dans l'exemple suivant, plus_plus_100 (x) est la vérité si x> 100:

>>>

>>> def Greater_than_100(X):
...     revenir X > 100
...

>>> liste(filtre(Greater_than_100, [[[[1, 111, 2, 222, 3, 333]))
[111, 222, 333]

Dans ce cas, plus_plus_100 () est la vérité pour les articles 111, 222, et 333, donc ces éléments restent, alors que 1, 2, et 3 sont rejetés. Comme dans les exemples précédents, plus_plus_100 () est une fonction courte, et vous pouvez la remplacer par un lambda expression à la place:

>>>

>>> liste(filtre(lambda X: X > 100, [[[[1, 111, 2, 222, 3, 333]))
[111, 222, 333]

Les caractéristiques de l'exemple suivant gamme(). plage (n) produit un itérateur qui donne les entiers de 0 à n - 1. L'exemple suivant utilise filtre() pour sélectionner uniquement les nombres pairs de la liste et filtrer les nombres impairs:

>>>

>>> liste(gamme(dix))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> def est même(X):
...     revenir X % 2 == 0
...
>>> liste(filtre(est même, gamme(dix)))
[0, 2, 4, 6, 8]

>>> liste(filtre(lambda X: X % 2 == 0, gamme(dix)))
[0, 2, 4, 6, 8]

Voici un exemple utilisant une méthode de chaîne intégrée:

>>>

>>> animaux = [[[["chat", "Chat", "CHAT", "chien", "Chien", "CHIEN", "émeu", "Émeu", "ÉMEU"]

>>> def toutes en majuscules(s):
...     revenir s.isupper()
...
>>> liste(filtre(toutes en majuscules, animaux))
['CAT', 'DOG', 'EMU']

>>> liste(filtre(lambda s: s.isupper(), animaux))
['CAT', 'DOG', 'EMU']

Rappelez-vous du didacticiel précédent sur les méthodes de chaîne s.isupper () Retour Vrai si tous les caractères alphabétiques de s sont en majuscules et Faux autrement.

Réduire un itérable à une valeur unique avec réduire()

réduire() applique une fonction aux éléments dans un itérable deux à la fois, en les combinant progressivement pour produire un seul résultat.

réduire() était autrefois une fonction intégrée à Python. Guido van Rossum n'a apparemment pas vraiment aimé réduire() et a plaidé pour son retrait de la langue entièrement. Voici ce qu’il avait à dire à ce sujet:

Alors maintenant réduire(). C’est en fait celui que j’ai toujours détesté le plus, car, mis à part quelques exemples impliquant + ou *, presque chaque fois que je vois un réduire() avec un argument de fonction non trivial, je dois prendre un stylo et du papier pour schématiser ce qui est réellement introduit dans cette fonction avant de comprendre ce que le réduire() est censé faire. Donc, dans mon esprit, l'applicabilité de réduire() est quasiment limité aux opérateurs associatifs, et dans tous les autres cas, il est préférable d'écrire explicitement la boucle d'accumulation. (La source)

Guido a en fait plaidé pour l'élimination des trois réduire(), carte(), et filtre() de Python. On ne peut que deviner son raisonnement. En l'occurrence, le mentionné précédemment compréhension de liste couvre les fonctionnalités fournies par toutes ces fonctions et bien plus encore. Vous pouvez en savoir plus en lisant Quand utiliser une compréhension de liste en Python.

Comme vous l’avez vu, carte() et filtre() restent des fonctions intégrées en Python. réduire() n'est plus une fonction intégrée, mais elle est disponible pour l'importation à partir d'un module de bibliothèque standard, comme vous le verrez ensuite.

Utiliser réduire(), vous devez l'importer à partir d'un module appelé functools. Cela est possible de plusieurs manières, mais la suivante est la plus simple:

de functools importer réduire

Suite à cela, l'interprète place réduire() dans l'espace de noms global et le rend disponible pour utilisation. Les exemples que vous verrez ci-dessous supposent que c'est le cas.

Appel réduire() Avec deux arguments

Le plus simple réduire() call prend une fonction et une itérable, comme indiqué ci-dessous:

réduire(, ) les usages , qui doit être une fonction qui prend exactement deux arguments, pour combiner progressivement les éléments dans . Commencer, réduire() invoque sur les deux premiers éléments de . Ce résultat est ensuite combiné avec le troisième élément, puis ce résultat avec le quatrième, et ainsi de suite jusqu'à ce que la liste soit épuisée. Puis réduire() renvoie le résultat final.

Guido avait raison quand il a dit que les applications les plus simples de réduire() sont ceux qui utilisent des opérateurs associatifs. Commençons par l'opérateur plus (+):

>>>

>>> def F(X, y):
...     revenir X + y
...

>>> de functools importer réduire
>>> réduire(F, [[[[1, 2, 3, 4, 5])
15

Cet appel à réduire() produit le résultat 15 from the list [1, 2, 3, 4, 5] as follows:

Reduce function illustration
reduce(f, [1, 2, 3, 4, 5])

This is a rather roundabout way of summing the numbers in the list! While this works fine, there’s a more direct way. Python’s built-in sum() returns the sum of the numeric values in an iterable:

>>>

>>> sum([[[[1, 2, 3, 4, 5])
15

Remember that the binary plus operator also concatenates strings. So this same example will progressively concatenate the strings in a list as well:

>>>

>>> reduce(F, [[[["cat", "dog", "hedgehog", "gecko"])
'catdoghedgehoggecko'

Again, there’s a way to accomplish this that most would consider more typically Pythonic. This is precisely what str.join() does:

>>>

>>> "".rejoindre([[[["cat", "dog", "hedgehog", "gecko"])
'catdoghedgehoggecko'

Now consider an example using the binary multiplication operator (*). Le factorial of a positive integer n is defined as follows:

Definition of factorial

You can implement a factorial function using reduce() et range() as shown below:

>>>

>>> def multiply(X, y):
...     return X * y
...

>>> def factorial(n):
...     de functools import reduce
...     return reduce(multiply, range(1, n + 1))
...

>>> factorial(4)  # 1 * 2 * 3 * 4
24
>>> factorial(6)  # 1 * 2 * 3 * 4 * 5 * 6
720

Once again, there’s a more straightforward way to do this. Vous pouvez utiliser factorial() provided by the standard math module:

>>>

>>> de math import factorial

>>> factorial(4)
24
>>> factorial(6)
720

As a final example, suppose you need to find the maximum value in a list. Python provides the built-in function max() to do this, but you could use reduce() as well:

>>>

>>> max([[[[23, 49, 6, 32])
49

>>> def greater(X, y):
...     return X si X > y else y
...

>>> de functools import reduce
>>> reduce(greater, [[[[23, 49, 6, 32])
49

Notice that in each example above, the function passed to reduce() is a one-line function. In each case, you could have used a lambda function instead:

>>>

>>> reduce(lambda X, y: X + y, [[[[1, 2, 3, 4, 5])
15
>>> reduce(lambda X, y: X + y, [[[["foo", "bar", "baz", "quz"])
'foobarbazquz'

>>> def factorial(n):
...     de functools import reduce
...     return reduce(lambda X, y: X * y, range(1, n + 1))
...
>>> factorial(4)
24
>>> factorial(6)
720

>>> reduce((lambda X, y: X si X > y else y), [[[[23, 49, 6, 32])
49

This is a convenient way to avoid placing an otherwise unneeded function into the namespace. On the other hand, it may be a little harder for someone reading the code to determine your intent when you use lambda instead of defining a separate function. As is often the case, it’s a balance between readability and convenience.

Calling reduce() With an Initial Value

There’s another way to call reduce() that specifies an initial value for the reduction sequence:

reduce(<F>, <iterable>, <init>)

When present, specifies an initial value for the combination. In the first call to , the arguments are and the first element of . That result is then combined with the second element of , and so on:

>>>

>>> def F(X, y):
...     return X + y
...

>>> de functools import reduce
>>> reduce(F, [[[[1, 2, 3, 4, 5], 100)  # (100 + 1 + 2 + 3 + 4 + 5)
115

>>> # Using lambda:
>>> reduce(lambda X, y: X + y, [[[[1, 2, 3, 4, 5], 100)
115

Now the sequence of function calls looks like this:

<img loading="lazy" class="img-fluid mx-auto d-block " src="https://files.realpython.com/media/t.4cc153eaaffb.png" width="2013" height="735" srcset="https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/t.4cc153eaaffb.png&w=503&sig=fba20ae659cadf2f63418f7719d29bbe43bc26cf 503w, https://robocrop.realpython.net/?url=https%3A//files.realpython.com/media/t.4cc153eaaffb.png&w=1006&sig=a11a9a12c98e12c51295b51b89bc42a104c5efe8 1006w, https://files.realpython.com/media/t.4cc153eaaffb.png 2013w" sizes="75vw" alt="Reduce function with argument" data-asset="2365"/>
reduce(f, [1, 2, 3, 4, 5], 100)

You could readily achieve the same result without reduce():

>>>

>>> 100 + sum([[[[1, 2, 3, 4, 5])
115

As you’ve seen in the above examples, even in cases where you can accomplish a task using reduce(), it’s often possible to find a more straightforward and Pythonic way to accomplish the same task without it. Maybe it’s not so hard to imagine why reduce() was removed from the core language after all.

That said, reduce() is kind of a remarkable function. The description at the beginning of this section states that reduce() combines elements to produce a single result. But that result can be a composite object like a list or a tuple. For that reason, reduce() is a very generalized higher-order function from which many other functions can be implemented.

For example, you can implement map() in terms of reduce():

>>>

>>> numbers = [[[[1, 2, 3, 4, 5]

>>> list(map(str, numbers))
['1', '2', '3', '4', '5']

>>> def custom_map(function, iterable):
...     de functools import reduce
...
...     return reduce(
...         lambda items, value: items + [[[[function(value)],
...         iterable,
...         [],
...     )
...
>>> list(custom_map(str, numbers))
['1', '2', '3', '4', '5']

You can implement filter() using reduce() as well:

>>>

>>> numbers = list(range(dix))
>>> numbers
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> def is_even(X):
...     return X % 2 == 0
...

>>> list(filter(is_even, numbers))
[0, 2, 4, 6, 8]

>>> def custom_filter(function, iterable):
...     de functools import reduce
...
...     return reduce(
...         lambda items, value: items + [[[[value] si function(value) else items,
...         iterable,
...         []
...     )
...
>>> list(custom_filter(is_even, numbers))
[0, 2, 4, 6, 8]

In fact, any operation on a sequence of objects can be expressed as a reduction.

Conclusion

Functional programming is a programming paradigm in which the primary method of computation is evaluation of pure functions. Although Python is not primarily a functional language, it’s good to be familiar with lambda, map(), filter(), et reduce() because they can help you write concise, high-level, parallelizable code. You’ll also see them in code that others have written.

In this tutorial, you learned:

  • Quoi functional programming est
  • Comment functions in Python are first-class citizens, and how that makes them suitable for functional programming
  • How to define a simple anonymous function avec lambda
  • How to implement functional code with map(), filter(), et reduce()

With that, you’ve reached the end of this introductory series on the fundamentals of working with Python. Toutes nos félicitations! You now have a solid foundation for making useful programs in an efficient, Pythonic style.

If you’re interested in taking your Python skills to the next level, then you can check out some more intermediate and advanced tutorials. You can also check out some Python project ideas to start putting your Python superpowers on display. Happy coding!

[ad_2]