Maison > Article > développement back-end > Un examen plus approfondi des fonctions du décorateur Python
Cet article vous apporte des connaissances pertinentes sur python, qui organise principalement les problèmes liés aux fonctions des décorateurs, y compris le processus de formation, l'essence et la fonction, l'avancement et l'optimisation des décorateurs, etc. Ce qui suit est Jetons un coup d'œil, j'espère que cela aidera tout le monde .
Apprentissage recommandé : python
Si j'écris une fonction f
def f(): print('hello')
et que je veux connaître le temps qu'il faut pour exécuter cette fonction, c'est facile à faire, il me suffit de changer le code en ce qui suit
import time def f(): start = time.time() #获取程序执行开始的时间 print('hello') end = time.time() #获取程序执行结束的时间 print(end - start) #得出函数f执行所要时间 f()
Mais ensuite j'ai écrit d'innombrables fonctions f2, f3...fn. Je voulais connaître le temps nécessaire pour exécuter chaque fonction. Ne serait-ce pas très ennuyeux si je les modifiais toutes comme ci-dessus ? Ce n’est toujours pas possible, car cela poserait trop de problèmes. Ce qu'il faut faire? J'ai donc eu une idée et j'ai écrit une fonction de minuterie. . .
import time def timer(func): start = time.time() func() print(time.time() - start) def f(): print('hello') def f2(): print('xorld') timer(f) timer(f2)
Cela n'a-t-il pas l'air beaucoup plus simple ? Peu importe le nombre de fonctions que nous écrivons, nous pouvons appeler cette fonction de timing pour calculer le temps d'exécution de la fonction
Mais si je veux juste appeler cette fonction de la manière originale f1(), f2(), fn(), le La fonction sera exécutée de la manière originale. En partant du principe que le résultat de sortie reste inchangé, la fonction de calcul du temps peut être ajoutée. Au lieu d'appeler timer(f), timer(f2) peut calculer le temps.
Vous saurez comment résoudre ce problème après avoir lu la fonction décorateur ci-dessous
Ce qui suit est une version simple du code pour résoudre le problème ci-dessus :
import time def f(): print('hello') def timer(func): def inner(): start = time.time() func() print(time.time() - start) return inner f = timer(f) f()
C'est ce que j'ai. J'ai dit que je voulais juste appeler cette fonction de la manière originale f1(), f2(), fn(). La fonction peut également augmenter le temps de calcul sans modifier le résultat de l'exécution d'origine, mais je dois quand même l'exécuter dans la fonction f. Trouvez-vous ennuyeux d'écrire f = timer(f) dans cette chaîne de code ? Les développeurs Python trouvent également cela ennuyeux, alors les développeurs Python nous fournissent un sucre syntaxique pour résoudre ce problème !
Remplacez f = timer(f) par @timmer C'est une phrase de sucre syntaxique.
import time def timer(func): def inner(): start = time.time() func() print(time.time() - start) return inner @timer #==> 写着这句话就相当于执行了f = timer(f) def f(): print('hello') f()
1. Essence
L'essence du décorateur est une fonction de fermeture
2. Fonction
Sans modifier la fonction d'origine et sa méthode d'appel Étendre la fonction de la fonction originale dans certaines circonstances
Les décorateurs que nous venons d'écrire décorent tous une fonction sans paramètres. Que dois-je faire maintenant si je veux décorer une fonction avec des paramètres ?
import time def timer(func): def inner(a): start = time.time() func(a) print(time.time() - start) return inner @timer def f(a): print(a) f('hello')
En fait, il n'est pas difficile de décorer des fonctions avec des paramètres, mais si vous avez deux fonctions, les paramètres qui doivent être transmis sont différents ,Par exemple, la fonction func1 a deux paramètres func1(a,b), la fonction func2 n'a qu'un seul paramètre func2(a), et elles veulent toutes les deux être décorées avec ce décorateur pour calculer le temps d'exécution de la fonction ? Ce qu'il faut faire? Utilisez ensuite le code suivant.
import time def timer(func): def inner(*args,**kwargs): start = time.time() re = func(*args,**kwargs) print(time.time() - start) return re return inner @timer #==> func1 = timer(func1) def func1(a,b): print('in func1') @timer #==> func2 = timer(func2) def func2(a): print('in func2 and get a:%s'%(a)) return 'fun2 over' func1('aaaaaa','bbbbbb') print(func2('aaaaaa')) 输出结果: in func1 0.0 in func2 and get a:aaaaaa 0.0 fun2 over
Maintenant, le problème des paramètres a été parfaitement résolu, mais que se passe-t-il si votre fonction a une valeur de retour ? Vous ne pouvez pas obtenir la valeur de retour en utilisant le code ci-dessus. Alors, comment résoudre ce problème ? Alors regardez le code ci-dessous !
import time def timer(func): def inner(*args,**kwargs): start = time.time() re = func(*args,**kwargs) print(time.time() - start) return re return inner @timer #==> func2 = timer(func2) def func2(a): print('in func2 and get a:%s'%(a)) return 'fun2 over' func2('aaaaaa') print(func2('aaaaaa')) 输出结果: in func2 and get a:aaaaaa 0.0 in func2 and get a:aaaaaa 0.0 fun2 over
Parfois, nous utiliserons également plusieurs décorateurs pour décorer la même fonction.
ef wrapper1(func): #func ----- f def inner1(): print('wrapper1 ,before func') func() print('wrapper1 ,after func') return inner1 def wrapper2(func): def inner2(): print('wrapper2 ,before func') func() print('wrapper2 ,after func') return inner2 @wrapper2 #f = wrapper2(f) ----->> wrapper2(inner1) == inner2 @wrapper1 #f = wrapper1(f) = inner def f(): print('in f') f() #===>>inner2 #多个装饰器装饰同一个函数 输出结果: wrapper2 ,before func wrapper1 ,before func in f wrapper1 ,after func wrapper2 ,after func
Le décorateur ci-dessus est déjà très beau, mais il y a un autre problème si je donne d'innombrables fonctions dans le code. sucre syntaxique de @timer ajouté. Si je ne veux plus l'utiliser, ne devrais-je pas le commenter à nouveau et travailler jour et nuit pendant 3 jours ? N'est-ce pas particulièrement gênant ? Afin de mieux recycler les décorateurs lorsqu'ils ne sont pas utilisés au lieu de les annoter ou de les supprimer un par un, nous introduisons le concept de décorateurs avec paramètres
''' 为了使装饰器不用时能够更好的回收而不是一个一个去注释或者删除 我们引入带参数的装饰器概念 ''' import time '''FLAGE的目的是用它控制装饰器的开关, 那么当我们不用的时候就不要一个一个去注释只需将True改为False就行''' FLAGE = True def timmer_out(flag): def timmer(func): def inner(*args,**kwargs): if flag: start = time.time() ret = func(*args,**kwargs) end = time.time() print(end - start) return ret else: ret = func(*args, **kwargs) return ret return inner return timmer @timmer_out(FLAGE) #timmer_out(FLAGE) # 也相当于执行 timmer_out(FLAGE)--->>返回timmer———————>>@timmer(wahaha = timmer(wahaha)) def wahaha(): time.sleep(0.1) #不休息的话函数执行的太快难以计算时间 print('wahahahahahaha') wahaha() @timmer_out(FLAGE) def erguotou(): time.sleep(0.1) #不休息的话函数执行的太快难以计算时间 print('erguotoutoutou') erguotou() 输出结果: wahahahahahaha 0.10152268409729004 erguotoutoutou 0.10795140266418457
''' print(wahaha.__name__) #查看字符串格式的函数名 print(wahaha.__doc__) #查看一个函数的注释 ''' #下面用__name__查看holiday的函数名 from functools import wraps def wrapper(func): @wraps(func) #加在最内层函数正上方 def inner(*args,**kwargs): print('在被装饰的函数执行之前做的事') ret = func(*args,**kwargs) print('在被装饰的函数执行之后做的事') return ret return inner @wrapper #holiday = wrapper(holiday) def holiday(day): ''' 这是一个放假通知 :param day: :return: ''' print('全体放假%s天'%day) return '好开心' print(holiday.__name__) print(holiday.__doc__) ''' 结果是inner和None 但我们想要的是打印holiday的字符串格式的函数名和函数的注释这时该怎么办? 解决方法就是 from functools import wraps 使用语法是@wraps(被装饰的函数名) ''' 输出结果: holiday 这是一个放假通知 :param day: :return:
1、开放封闭原则
1.对原函数的功能扩展是开放的
为什么要对功能扩展开放呢?
对于任何一个程序来说,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。所以我们必须允许后来扩展、添加新功能。
2.对修改是封闭的
为什么要对修改封闭呢?
就像我们刚刚提到的,因为我们写的一个函数,很有可能在其他地方已经被导入使用了,如果这个时候我们对其进行了修改,很有可能影响其他已经正在使用该函数的代码。
装饰器就完美遵循了这个开放封闭原则。这就是学装饰器的初衷
1、装饰器的固定格式(模板)
#格式一 def timer(func): def inner(*args,**kwargs): '''执行函数之前要做的''' re = func(*args,**kwargs) '''执行函数之后要做的''' return re return inner #格式二 from functools import wraps def deco(func): @wraps(func) #加在最内层函数正上方 def wrapper(*args,**kwargs): return func(*args,**kwargs) return wrapper
推荐学习:python
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!