Python Advanced : description détaillée des fonctions d'ordre supérieur

高洛峰
Libérer: 2017-03-09 11:03:12
original
1524 Les gens l'ont consulté

Cet article parle de Python avancé : explication détaillée des fonctions d'ordre élevé. Les amis dans le besoin peuvent se référer à

Programmation fonctionnelle

La fonction est une sorte d'encapsulation prise en charge par le module intégré de Python. . En divisant de grandes sections de code en fonctions et en appelant des fonctions couche par couche, nous pouvons décomposer des tâches complexes en tâches simples. Cette décomposition peut être appelée programmation orientée processus. Les fonctions constituent l'unité de base de la programmation orientée processus.

Programmation fonctionnelle (veuillez noter le mot supplémentaire « formule ») - Programmation fonctionnelle, bien qu'elle puisse également être attribuée à la programmation orientée processus, ses idées sont plus proches des calculs mathématiques.

Il faut d'abord comprendre les notions d'ordinateur et d'informatique.

Au niveau de l'ordinateur, le processeur exécute des codes d'instructions pour l'addition, la soustraction, la multiplication et la division, ainsi que divers jugements conditionnels et instructions de saut. Par conséquent, le langage assembleur est le langage le plus proche de l'ordinateur.

Le calcul fait référence au calcul au sens mathématique. Plus le calcul est abstrait, plus il est éloigné du matériel informatique.

Correspond aux langages de programmation, c'est-à-dire que le langage de niveau inférieur est plus proche de l'ordinateur, a un niveau d'abstraction inférieur et a une efficacité d'exécution plus élevée, comme le langage de niveau supérieur est plus proche ; à l'informatique, a un niveau d'abstraction plus élevé et une efficacité d'exécution inférieure, comme le langage Lisp.

La programmation fonctionnelle est un paradigme de programmation avec un haut degré d'abstraction. Les fonctions écrites dans des langages de programmation fonctionnels purs n'ont pas de variables. Par conséquent, pour toute fonction, tant que l'entrée est certaine, la sortie le sera. certain. On dit que cette fonction pure n’a aucun effet secondaire. Dans les langages de programmation qui permettent l'utilisation de variables, puisque le statut de la variable à l'intérieur de la fonction est incertain, la même entrée peut donner lieu à des sorties différentes. Par conséquent, ce type de fonction a des effets secondaires.

Une caractéristique de la programmation fonctionnelle est qu'elle permet à la fonction elle-même d'être passée dans une autre fonction en tant que paramètre, et elle permet également de renvoyer une fonction !

Python fournit un support partiel pour la programmation fonctionnelle. Puisque Python permet l’utilisation de variables, Python n’est pas un langage de programmation purement fonctionnel.

Fonction d'ordre supérieur

La fonction d'ordre supérieur est appelée fonction d'ordre supérieur en anglais. Que sont les fonctions d’ordre supérieur ? Nous utilisons le code réel comme exemple pour approfondir les concepts étape par étape.

Les variables peuvent pointer vers des fonctions

Prenons comme exemple la fonction de valeur absolue intégrée de Python abs() Pour appeler cette fonction, utilisez le code suivant :

> >>abs(-10)10

Mais et si vous n'écriviez que des abdos ?

>>> abs

On peut voir que abs(-10) est un appel de fonction, et abs est la fonction elle-même.

Pour obtenir le résultat de l'appel de fonction, nous pouvons attribuer le résultat à une variable :

>>> x = abs(-10)>>> >

Mais que se passe-t-il si la fonction elle-même est affectée à une variable ?

>>> f = abs

>>> f


Conclusion : la fonction elle-même est également Peut être affecté à des variables, c'est-à-dire : les variables peuvent pointer vers des fonctions.

Si une variable pointe vers une fonction, la fonction peut-elle être appelée via la variable ? Vérifiez-le avec le code :

>>> f = abs>>> f(-10)10


Succès ! Cela signifie que la variable f pointe désormais vers la fonction abs elle-même. Appeler directement la fonction abs() revient exactement à appeler la variable f().

Le nom de la fonction est aussi une variable

Alors, quel est le nom de la fonction ? Le nom de la fonction est en fait la variable pointant vers la fonction ! Pour la fonction abs(), le nom de la fonction abs peut être considéré comme une variable, qui pointe vers une fonction capable de calculer la valeur absolue !

Que se passera-t-il si les abdominaux pointent vers d'autres objets ?

>>> abs = 10

>>> abs(-10)
Traceback (dernier appel le plus récent) :
Fichier "" , ligne 1, dans
TypeError : l'objet 'int' n'est pas appelable

Après avoir pointé abs sur 10, la fonction ne peut pas être appelée via abs(-10) ! Car la variable abs ne pointe plus vers la fonction valeur absolue mais vers un entier 10 !

Bien sûr, le code réel ne doit pas être écrit comme ceci pour illustrer que le nom de la fonction est également une variable. Pour restaurer la fonction abs, redémarrez l'environnement interactif Python.

Remarque : Puisque la fonction abs est en fait définie dans le module import internals, pour modifier le pointeur de la variable abs afin qu'elle prenne effet dans d'autres modules, utilisez import internalins.abs = 10.

Passer en fonction

Puisque les variables peuvent pointer vers des fonctions et que les paramètres des fonctions peuvent recevoir des variables, alors une fonction peut recevoir une autre fonction en tant que paramètre. Ce type de fonction est appelé supérieur. fonction de commande.

Une fonction d'ordre supérieur la plus simple :

def add(x, y, f) : return f(x) f(y)

Quand nous Quand en appelant add(-5, 6, abs), les paramètres x, y et f reçoivent respectivement -5, 6 et abs. D'après la définition de la fonction, nous pouvons déduire le processus de calcul comme :

x = -. 5
y = 6
f = abs
f(x) f(y) ==> abs(-5) abs(6) ==> 🎜>Utilisez Vérifier le code :

>>> add(-5, 6, abs)11

Écrire une fonction d'ordre supérieur consiste à autoriser les paramètres de la fonction pour recevoir d'autres fonctions.

Résumé

Passer des fonctions en tant que paramètres. Ces fonctions sont appelées fonctions d'ordre supérieur. La programmation fonctionnelle fait référence à ce paradigme de programmation hautement abstrait.

map/reduce

Python a des fonctions map() et reduction() intégrées.

Si vous avez lu le célèbre article de Google "MapReduce: Simplified Data Processing on Large Clusters", vous pouvez à peu près comprendre le concept de map/reduce.

Regardons d’abord la carte. La fonction map() reçoit deux paramètres, l'un est une fonction et l'autre est un itérable. La carte applique tour à tour la fonction passée à chaque élément de la séquence et renvoie le résultat sous la forme d'un nouvel itérateur.

Par exemple, par exemple, nous avons une fonction f(x)=x2, et nous voulons appliquer cette fonction à une liste [1, 2, 3, 4, 5, 6, 7, 8, 9]. Vous pouvez utiliser map() pour l'implémenter comme suit :

Maintenant, nous utilisons du code Python pour l'implémenter : Python Advanced : description détaillée des fonctions dordre supérieur

>> > def f(x): ... return x * x

...>>> 9])>>> ; list(r)

[1, 4, 9, 16, 25, 36, 49, 64, 81]



Le premier paramètre transmis à map() est f, c'est-à-dire l'objet fonction lui-même. Puisque le résultat r est un itérateur et que Iterator est une séquence paresseuse, il utilise la fonction list() pour lui permettre de calculer la séquence entière et de renvoyer une liste.

Vous pensez peut-être que vous n'avez pas besoin de la fonction map(), vous pouvez écrire une boucle et calculer le résultat :

L = []for n in [1, 2, 3 , 4, 5, 6, 7, 8, 9]:

L.append(f(n))

print(L)



est effectivement possible, mais, du ci-dessus le code de boucle, pouvez-vous comprendre en un coup d'œil « appliquer f(x) à chaque élément de la liste et générer une nouvelle liste en conséquence » ?

Ainsi, map(), en tant que fonction d'ordre élevé, fait abstraction des règles de fonctionnement. Par conséquent, nous pouvons non seulement calculer f(x)=x2 simple, mais également calculer n'importe quelle fonction complexe, telle que, Convertissez tous les nombres de cette liste en chaînes :

>>> list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9]))[ '1', '2', '3', '4', '5', '6', '7', '8', '9']

Une seule ligne de code .

Regardez l'utilisation de réduire. réduire applique une fonction à une séquence [x1, x2, x3, ...]. Cette fonction doit recevoir deux paramètres. réduire continue le calcul cumulé du résultat avec l'élément suivant de la séquence. L'effet est :

<.>reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

Par exemple, additionnez une séquence, vous peut utiliser réduire pour implémenter :


>>> from functools import réduire>>> def add(x, y):... return x y

...>> ; > réduire(ajouter, [1, 3, 5, 7, 9])25

Bien sûr, l'opération de somme peut être directement effectuée à l'aide de la fonction intégrée sum() de Python, et là il n'est pas nécessaire d'utiliser la réduction.

Mais si vous souhaitez transformer la séquence [1, 3, 5, 7, 9] en l'entier 13579, réduire peut être utile :

>>> importer réduire> ;>> def fn(x, y):... return x * 10 y

...>>> )13579

Cet exemple en lui-même n'est pas très utile, mais si l'on considère que la chaîne str est aussi une séquence, on peut légèrement modifier l'exemple ci-dessus et utiliser map(), on peut écrire pour convertir str dans la fonction Int :

>>> from functools import reduction>>> def fn(x, y):... return x * 10 y

...> > ;> def char2num(s) :... return {'0' : 0, "1" : 1, "2" : 2, "3" : 3, "4" : 4, "5" : 5 , '6' : 6, '7' : 7, '8' : 8, '9' : 9}[s]

...>>> réduire(fn, map(char2num, '13579 ' ))13579


organisé en fonction str2int est :

depuis functools import réduitef str2int(s) : def fn(x, y) : return x * 10 y def char2num(s) : return {'0' : 0, '1' : 1, '2' : 2 , '3' : 3, '4' : 4, '5' : 5, '6' : 6, '7' : 7, '8' : 8, '9' : 9}[s] return réduire(fn , map(char2num, s))

peut également être simplifié davantage à l'aide de la fonction lambda :

from functools import réduit char2num(s): return {'0': 0, ' 1' : 1, '2' : 2, '3' : 3, '4' : 4, '5' : 5, '6' : 6, '7' : 7, '8' : 8, '9'. : 9}[s]def str2int(s): return réduire(lambda x, y: x * 10 y, map(char2num, s))

C'est-à-dire, en supposant que Python ne fournisse pas d'int (), vous pouvez écrire vous-même une fonction pour convertir une chaîne en entier, et cela ne nécessite que quelques lignes de code !

L'utilisation de la fonction lambda sera présentée plus tard.

filter

La fonction filter() intégrée de Python est utilisée pour filtrer les séquences.

Semblable à map(), filter() reçoit également une fonction et une séquence. Contrairement à map(), filter() applique tour à tour la fonction transmise à chaque élément, puis décide de conserver ou de supprimer l'élément selon que la valeur de retour est True ou False.

Par exemple, dans une liste, pour supprimer les nombres pairs et ne conserver que les nombres impairs, vous pouvez écrire :

def is_odd(n) : return n % 2 == 1

list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))# Résultat : [1, 5, 9, 15]

Mettre un séquence dans Pour supprimer la chaîne vide, vous pouvez écrire :

def not_empty(s): return s and s.strip()

list(filter(not_empty, ['A', ' ' , 'B', Aucun, 'C', ' ']))# Résultat : ['A', 'B', 'C']

On voit que plus la fonction de commande filter() est utilisée, la clé est d'implémenter correctement une fonction "filtre".

Notez que la fonction filter() renvoie un Iterator, qui est une séquence paresseuse, donc pour forcer filter() à compléter les résultats du calcul, vous devez utiliser la fonction list() pour obtenir tous les résultats et renvoie la liste.

trié

Algorithme de tri

Le tri est également un algorithme souvent utilisé dans les programmes. Que le tri à bulles ou le tri rapide soit utilisé, le cœur du tri consiste à comparer les tailles de deux éléments. S'il s'agit d'un nombre, nous pouvons le comparer directement, mais que se passe-t-il s'il s'agit d'une chaîne ou de deux dictés ? La comparaison directe de grandeurs mathématiques n’a aucun sens, le processus de comparaison doit donc être abstrait à travers des fonctions.

La fonction sorted() intégrée de Python peut trier la liste :

>>> , -12, 5, 9, 36]

De plus, la fonction sorted() est également une fonction d'ordre supérieur. Elle peut également recevoir une fonction clé pour implémenter un tri personnalisé, comme par. valeur absolue Tri par taille :

>>> trié([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21 , 36 ]

La fonction spécifiée par key agira sur chaque élément de la liste et sera triée selon le résultat renvoyé par la fonction key. Comparez la liste originale et la liste traitée avec key=abs :

list = [36, 5, -12, 9, -21]keys = [36, 5, 12, 9, 21]

Ensuite la fonction sorted() trie par clés et renvoie les éléments correspondants de la liste selon la relation correspondante :

résultat du tri des clés => [5, 9, 12, 21, 36 ] > >
>>> trié(['bob', 'à propos', 'Zoo', 'Crédit'])['Crédit', 'Zoo', 'à propos', 'bob']

Par défaut, le tri des chaînes est basé sur la comparaison de la taille ASCII. Puisque 'Z'

Maintenant, nous proposons que le tri ignore la casse et trie par ordre alphabétique. Pour implémenter cet algorithme, il n'est pas nécessaire d'apporter des modifications majeures au code existant, tant que nous pouvons utiliser une fonction clé pour mapper la chaîne à un tri ignorant la casse. Comparer deux chaînes en ignorant la casse signifie en fait changer d'abord les chaînes en majuscules (ou minuscules), puis les comparer.


De cette façon, nous passons la fonction clé à sorted pour obtenir un tri qui ignore la casse :

>>> , 'Credit'], key=str.lower)

['about', 'bob', 'Credit', 'Zoo']

Pour inverser le tri, aucune modification n'est requise clé fonction, vous pouvez passer le troisième paramètre reverse=True :

>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str. lower , reverse=True)
['Zoo', 'Credit', 'bob', 'about']

Comme le montrent les exemples ci-dessus, la capacité d'abstraction d'ordre supérieur les fonctions sont très puissantes et le code de base peut rester très simple.

Résumé

sorted() est également une fonction d'ordre supérieur. La clé du tri avec sorted() est d’implémenter une fonction de mappage.

Fonction de retour

Fonction comme valeur de retour

En plus d'accepter des fonctions comme paramètres, les fonctions d'ordre supérieur peuvent également renvoyer des fonctions comme valeurs de résultat.

Implémentons la sommation d'un paramètre variable. Habituellement, la fonction somme est définie comme ceci :

def calc_sum(*args):
ax = 0 for n in args:
ax = ax n return ax

Cependant, que se passe-t-il si la somme n'a pas besoin d'être calculée immédiatement, mais est calculée selon les besoins dans le code suivant ? Au lieu de renvoyer le résultat de la sommation, vous pouvez renvoyer la fonction de sommation :

def lazy_sum(*args): def sum():
ax = 0 for n in args:
ax = ax n return axe return sum

Lorsque nous appelons lazy_sum(), ce qui est renvoyé n'est pas le résultat de la sommation, mais la fonction de sommation : = lazy_sum(1, 3, 5, 7, 9)

>>> f

.sum at 0x101c6ed90>


Appel Le résultat de la somme est effectivement calculé lorsque la fonction f est utilisée :

>>> f()25


Dans cet exemple, nous le définissons dans la fonction lazy_sum Function sum, et la fonction interne sum peut faire référence aux paramètres et locaux variables de la fonction externe lazy_sum. Lorsque lazy_sum renvoie la somme de la fonction, les paramètres et variables pertinents sont enregistrés dans la fonction renvoyée. C'est ce qu'on appelle la "Closure". La structure du programme a une grande puissance.

Veuillez noter encore une chose, lorsque nous appelons lazy_sum(), chaque appel renverra une nouvelle fonction, même si les mêmes paramètres sont transmis :

>>> somme_paresseuse(1, 3, 5, 7, 9)>>> f2 = somme_paresseuse(1, 3, 5, 7, 9)>f1==f2False


Les résultats des appels de f1() et f2() ne s'affectent pas.

Fermeture

Notez que la fonction renvoyée fait référence à la variable locale args dans sa définition, donc lorsqu'une fonction renvoie une fonction, ses variables locales internes sont également référencées par la nouvelle fonction, donc la fermeture est facile à utiliser, mais pas facile à mettre en œuvre.

Un autre problème à noter est que la fonction renvoyée n'est pas exécutée immédiatement, mais n'est exécutée que lorsque f() est appelée. Regardons un exemple :

def count():

fs = [] for i in range(1, 4): def f(): return i*i

fs.append( f) return fs

f1, f2, f3 = count()


Dans l'exemple ci-dessus, chaque fois qu'il boucle, une nouvelle fonction est créée, puis le All créé trois fonctions sont revenues.

Vous pensez peut-être que les résultats de l'appel de f1(), f2() et f3() devraient être 1, 4, 9, mais les résultats réels sont :

>>> ; f1() 9>>> f2()9>>> La raison en est que la fonction renvoyée fait référence à la variable i, mais elle n'est pas exécutée immédiatement. Au moment où les trois fonctions reviennent, la variable i à laquelle elles font référence est devenue 3, donc le résultat final est 9.

Une chose à garder à l'esprit lors du retour d'une fermeture est la suivante : la fonction de retour ne doit faire référence à aucune variable de boucle ou à des variables qui changeront par la suite.

Et si vous devez référencer une variable de boucle ? La méthode consiste à créer une autre fonction et à utiliser les paramètres de la fonction pour lier la valeur actuelle de la variable de boucle. Quelle que soit la façon dont la variable de boucle change par la suite, la valeur liée au paramètre de fonction reste inchangée :

def. count(): def f(j):           def g():                                                                            '   ' à ' s ’ s ’ s t ‐ ‐                                                                                    ) est exécuté immédiatement, donc la valeur actuelle de i est passé dans f() return fs

Regardez à nouveau le résultat :

>>> f1, f2, f3 = count()>> )4>>> f3()9


L'inconvénient est que le code est plus long et que la fonction lambda peut être utilisée pour raccourcir le code.

Résumé

Une fonction peut renvoyer un résultat de calcul ou une fonction.

Lorsque vous renvoyez une fonction, n'oubliez pas que la fonction n'est pas exécutée et ne faites référence à aucune variable susceptible de changer dans la fonction renvoyée.

Fonction anonyme

Lorsque nous transmettons une fonction, parfois nous n'avons pas besoin de définir explicitement la fonction. Il est plus pratique de transmettre directement la fonction anonyme.

En Python, la prise en charge des fonctions anonymes est limitée. Toujours en prenant comme exemple la fonction map(), lors du calcul de f(x)=x2, en plus de définir une fonction de f(x), vous pouvez aussi passer directement une fonction anonyme :

> >> liste (carte(lambda x : x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]))[1, 4, 9, 16, 25, 36, 49 , 64, 81]

Comme le montre la comparaison, la fonction anonyme lambda x: x * x est en fait :

def f(x) : return x * x


Le mot-clé lambda représente une fonction anonyme, et le x avant les deux points représente les paramètres de la fonction.

Les fonctions anonymes ont une limitation, c'est-à-dire qu'elles ne peuvent avoir qu'une seule expression. Il n'est pas nécessaire d'écrire return La valeur de retour est le résultat de l'expression.

Il y a un avantage à utiliser des fonctions anonymes, car la fonction n'a pas de nom, vous n'avez donc pas à vous soucier des conflits de noms de fonction. De plus, la fonction anonyme est également un objet fonction. Vous pouvez également attribuer la fonction anonyme à une variable puis utiliser la variable pour appeler la fonction :

>>> * x
>>> f
à 0x101c6ef28>
>>> >De même, vous pouvez renvoyer la fonction anonyme comme valeur de retour, par exemple :

def build(x, y): return lambda: x * x y * y

Résumé


Paire Python La prise en charge des fonctions anonymes est limitée et seules certaines situations simples peuvent utiliser des fonctions anonymes.

Fonction partielle

Le module functools de Python fournit de nombreuses fonctions utiles, dont l'une est la fonction partielle. Il convient de noter que la fonction partielle est ici différente de la fonction partielle au sens mathématique.

Lors de l'introduction des paramètres de fonction, nous avons mentionné qu'en définissant les valeurs par défaut des paramètres, la difficulté d'appel de fonction peut être réduite. Les fonctions partielles peuvent également le faire. Par exemple :

La fonction int() peut convertir une chaîne en entier. Lorsqu'une seule chaîne est transmise, la fonction int() utilise par défaut la conversion décimale :

>> > int('12345')12345

Mais la fonction int() fournit également un paramètre de base supplémentaire, la valeur par défaut est 10. Si vous passez le paramètre base, vous pouvez effectuer une conversion N-base :


>>> int('12345', base=8)5349

>>> ' 12345', 16)74565

En supposant que nous voulons convertir un grand nombre de chaînes binaires, il est très gênant de passer int(x, base=2) à chaque fois, nous avons donc pensé que l'on puisse définir une fonction int2( ), base=2 est passé par défaut :

def int2(x, base=2) : return int(x, base)

De cette façon, nous convertissons le binaire Très pratique :


>>> int2('1000000')64>>> >functools.partial est pour nous aider. Pour créer une fonction partielle, nous n'avons pas besoin de définir nous-mêmes int2(). Nous pouvons directement utiliser le code suivant pour créer une nouvelle fonction int2 :

>>>. ; importer functools>>> int2 = functools .partial(int, base=2)>>> int2('1000000')64>>> >

Donc, un bref résumé de functools.partial La fonction consiste à corriger certains paramètres d'une fonction (c'est-à-dire définir des valeurs par défaut) et à renvoyer une nouvelle fonction. Il sera plus facile d'appeler cette nouvelle fonction.


Notez que la nouvelle fonction int2 ci-dessus réinitialise uniquement le paramètre de base à la valeur par défaut de 2, mais d'autres valeurs peuvent également être transmises lorsque la fonction est appelée :

>> ; > int2('1000000', base=10)1000000


Enfin, lors de la création d'une fonction partielle, vous pouvez en fait recevoir trois paramètres : objet de fonction, *args et **kw. in :

int2 = functools.partial(int, base=2)

corrige en fait la base de paramètres de mots-clés de la fonction int(), c'est-à-dire :


int2('10010')

est équivalent à :


kw = { 'base': 2 }int('10010', **kw)

Une fois transmis :


max2 = functools.partial(max, 10)

ajoutera automatiquement 10 à gauche dans le cadre de *args, c'est-à-dire :


max2(5, 6, 7)

équivaut à :


args = (10, 5, 6, 7)

max(* args)

Le résultat est 10.

Résumé

Lorsqu'une fonction a trop de paramètres et doit être simplifiée, vous pouvez utiliser functools.partial pour créer une nouvelle fonction. Cette nouvelle fonction peut corriger certains des paramètres de l'original. fonction, donc c'est plus simple lors de l'appel.



Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!