Quand je regardais le dépôt pip sur github, j'utilisais un décorateur intéressant, donc je vais le partager.
TL;DR --Le décorateur peut être utilisé non seulement pour modifier la fonction, mais aussi pour ** exécuter la fonction **.
Tout d'abord, quel type de valeur prend la variable globale lors de l'importation du package suivant? Les deux fonctions spam
et ʻegg sont des fonctions uniquement pour mettre à jour la variable globale
global_variable`.
mypackage/__init__.py
GLOBAL_VARIABLE = 0
def spam():
global_variable = 1
globals().update(locals())
def egg():
global global_variable
global_variable = 2
main.py
import mypackage
if __name__ == "__main__":
print(mypackage.global_variable)
La valeur de global_variable
n'a pas changé depuis sa déclaration, car nous ne faisons que définir la fonction et non l'exécuter. Bien entendu, le résultat de l'exécution est le suivant.
$python3 main.py
0
Alors que se passe-t-il si vous essayez d'appeler la fonction à la fin de mypackage / __ init __. Py
?
mypackage/__init__.py
GLOBAL_VARIABLE = 0
def spam():
global_variable = 1
globals().update(locals())
def egg():
global global_variable
global_variable = 2
spam()
egg()
Dans ce cas, la fonction est appelée et la valeur de «global_variable» est écrasée à la fois dans «spam» et «egg», le résultat de l'exécution est donc le suivant.
$python3 main.py
2
Cependant, avec cette méthode, si le nombre de fonctions que vous souhaitez exécuter augmente, vous devez écrire le code pour appeler autant, ce qui est gênant. C'est là que le ** décorateur ** entre en jeu.
Voici le problème principal. Jetons un coup d'œil au code. Considérez la fonction suivante call_aside
.
mypackage/__init__.py
global_variable = 0
def call_aside(f, *args, **kwargs):
f(*args, **kwargs)
return f
@call_aside
def spam():
global_variable = 1
globals().update(locals())
@call_aside
def egg():
global global_variable
global_variable = 2
main.py
import mypackage
if __name__ == "__main__":
print(mypackage.global_variable)
Quel est le résultat de l'exécution
$python3 main.py
2
On dirait! Au début, je n'en comprenais pas la raison, j'étais donc assez inquiète. Cependant, le mécanisme est simple une fois que vous l'avez compris. En se concentrant sur la fonction call_aside
,
def call_aside(f, *args, **kwargs):
f(*args, **kwargs) # <- execute f
return f
Et ainsi de suite, la fonction est appelée en interne. Par conséquent, juste en modifiant avec call_aside
, spam
et ʻegg sont exécutés lorsque mypackage est importé, donc la valeur de
global_variable` a changé comme indiqué ci-dessus. Dans ce cas, même si le nombre de fonctions que vous souhaitez exécuter au moment de l'importation augmente, il vous suffit de le décorer: tada:
Lors de l'examen des décorateurs Python, beaucoup expliquent les décorateurs qui ** utilisent des décorateurs pour "ajouter un traitement avant et après une fonction" et "renvoyer des fonctions avec un traitement ajouté avant et après" **. Je pense.
def decorator(f):
def wrapper(*args, **kwargs):
print("Prétraitement")
f(*args, **kwargs)
print("Post-traitement")
return wrapper
De cette manière, la fonction wrapper
est uniquement définie et non exécutée. Même si vous décorez une fonction avec ce décorateur, il n'aura aucun effet tel que la mise à jour de la valeur de la variable globale jusqu'à ce que vous appeliez la fonction décorée.
pypa/pip/blob/master/src/pip/_vendor/pkg_resources/__init__.py
Si vous pouvez lire et écrire en Python dans une certaine mesure, jetez un œil aux hubs git officiels tels que CPython
et Pypa
. Il y a un nombre infini de codes pour les Tsuyotsuyo, donc je pense qu'il y aura de nouvelles découvertes et des codes utiles.
Recommended Posts