Introduction
Cette section présente l'idée d'utiliser des fonctions pour créer d'autres fonctions.
This tutorial is from open-source community. Access the source code
💡 Ce tutoriel est traduit par l'IA à partir de la version anglaise. Pour voir la version originale, vous pouvez cliquer ici
Cette section présente l'idée d'utiliser des fonctions pour créer d'autres fonctions.
Considérez la fonction suivante.
def add(x, y):
def do_add():
print('Adding', x, y)
return x + y
return do_add
Il s'agit d'une fonction qui renvoie une autre fonction.
>>> a = add(3,4)
>>> a
<function add.<locals>.do_add at 0x7f27d8a38790>
>>> a()
Adding 3 4
7
Observez comment la fonction interne fait référence à des variables définies par la fonction externe.
def add(x, y):
def do_add():
## `x` et `y` sont définis au-dessus de `add(x, y)`
print('Adding', x, y)
return x + y
return do_add
Observez également que ces variables sont de quelque manière conservées en vie après que add()
ait terminé.
>>> a = add(3,4)
>>> a
<function do_add at 0x6a670>
>>> a()
Adding 3 4 ## D'où viennent ces valeurs?
7
Lorsqu'une fonction interne est renvoyée en tant que résultat, cette fonction interne est connue sous le nom de closure.
def add(x, y):
## `do_add` est un closure
def do_add():
print('Adding', x, y)
return x + y
return do_add
Fonctionnalité essentielle : Un closure conserve les valeurs de toutes les variables nécessaires pour que la fonction puisse fonctionner correctement plus tard. Pensez à un closure comme une fonction plus un environnement supplémentaire qui contient les valeurs des variables dont elle dépend.
Les closures sont une fonctionnalité essentielle de Python. Cependant, leur utilisation est souvent subtile. Applications courantes :
Considérez une fonction comme celle-ci :
def after(seconds, func):
import time
time.sleep(seconds)
func()
Exemple d'utilisation :
def greeting():
print('Hello Guido')
after(30, greeting)
after
exécute la fonction fournie... plus tard.
Les closures transportent des informations supplémentaires.
def add(x, y):
def do_add():
print(f'Adding {x} + {y} -> {x+y}')
return do_add
def after(seconds, func):
import time
time.sleep(seconds)
func()
after(30, add(2, 3))
## `do_add` a les références x -> 2 et y -> 3
Les closures peuvent également être utilisées comme technique pour éviter une répétition excessive de code. Vous pouvez écrire des fonctions qui génèrent du code.
L'une des fonctionnalités les plus puissantes des closures est leur utilisation dans la génération de code répétitif. Si vous vous reportez à l'exercice 5.7, rappelez-vous le code pour définir une propriété avec une vérification de type.
class Stock:
def __init__(self, name, shares, price):
self.name = name
self.shares = shares
self.price = price
...
@property
def shares(self):
return self._shares
@shares.setter
def shares(self, value):
if not isinstance(value, int):
raise TypeError('Expected int')
self._shares = value
...
Au lieu de taper répétitivement ce code à l'infini, vous pouvez le créer automatiquement à l'aide d'une closure.
Créez un fichier typedproperty.py
et mettez le code suivant dedans :
## typedproperty.py
def typedproperty(name, expected_type):
private_name = '_' + name
@property
def prop(self):
return getattr(self, private_name)
@prop.setter
def prop(self, value):
if not isinstance(value, expected_type):
raise TypeError(f'Expected {expected_type}')
setattr(self, private_name, value)
return prop
Maintenant, essayez-le en définissant une classe comme ceci :
from typedproperty import typedproperty
class Stock:
name = typedproperty('name', str)
shares = typedproperty('shares', int)
price = typedproperty('price', float)
def __init__(self, name, shares, price):
self.name = name
self.shares = shares
self.price = price
Essayez de créer une instance et de vérifier que la vérification de type fonctionne.
>>> s = Stock('IBM', 50, 91.1)
>>> s.name
'IBM'
>>> s.shares = '100'
... devrait générer un TypeError...
>>>
Dans l'exemple ci-dessus, les utilisateurs pourraient trouver des appels tels que typedproperty('shares', int)
un peu verbeux à taper - surtout s'ils sont répétés fréquemment. Ajoutez les définitions suivantes au fichier typedproperty.py
:
String = lambda name: typedproperty(name, str)
Integer = lambda name: typedproperty(name, int)
Float = lambda name: typedproperty(name, float)
Maintenant, réécrivez la classe Stock
pour utiliser ces fonctions à la place :
class Stock:
name = String('name')
shares = Integer('shares')
price = Float('price')
def __init__(self, name, shares, price):
self.name = name
self.shares = shares
self.price = price
Ah, c'est un peu mieux. Le principal enseignement ici est que les closures et les lambda
peuvent souvent être utilisés pour simplifier le code et éliminer la répétition ennuyeuse. Cela est souvent bénéfique.
Félicitations ! Vous avez terminé le laboratoire sur les fonctions de retour. Vous pouvez pratiquer d'autres laboratoires sur LabEx pour améliorer vos compétences.