ホームページ >バックエンド開発 >Python チュートリアル >Python デコレータ関数を詳しく見る
この記事では、デコレータの形成過程、本質と機能、高度化と最適化など、デコレータ関数に関する論点を中心に整理した python に関する関連知識を紹介します。 以下の内容を見てみましょう。皆様のお役に立てれば幸いです。
推奨学習: python
関数 f
def f(): print('hello')
を書く場合、この段落を知りたい関数の実行にかかる時間は扱いやすく、コードを次のように変更するだけです
import time def f(): start = time.time() #获取程序执行开始的时间 print('hello') end = time.time() #获取程序执行结束的时间 print(end - start) #得出函数f执行所要时间 f()
しかし、無数の関数 f2、f3...fn を書いたので、それぞれの時間がどれくらいかを知りたい関数の実行には時間がかかりますが、上記のように変更すると非常に面倒ではないでしょうか?面倒なのでまだ無理です。それではどうすればいいでしょうか?そこで私はアイデアを思いつき、タイマー関数を作成しました。 。 。
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)
これは非常にシンプルに見えませんか?作成した関数の数に関係なく、このタイミング関数を呼び出して関数の実行時間を計算できます
しかし、この関数を元の方法で呼び出したい場合は、f1()、f2()、fn (), この関数には、元の実行出力結果を変更せずに時間を計算する関数を追加することもできます。timer(f) を呼び出す代わりに、timer(f2) で時間を計算することもできます。
以下のデコレータ関数を読むと、この問題の解決方法がわかります。
次は解決策 A です。上記の質問のコードの簡単なバージョン:
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()
この文のままでは、この関数を元の方法で f1()、f2()、fn() で呼び出したいだけです。関数は結果を出力します。変更することを前提として、時間を計算する関数を追加することはできますが、関数 f を実行する前に、このコード列に f = timer(f) と書かなければなりません。 Python 開発者もこの問題を煩わしいと感じているため、この問題を解決するための 構文シュガー を提供してくれました。
f = timer(f) の代わりに @timmer を使用します。これは糖衣構文の文です。
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. 本質
デコレータの本質はクロージャ関数です
2. 関数元の関数とその呼び出しメソッドを変更せずに元の関数関数を拡張します
4. 装飾デコレーター - パラメーターと戻り値を持つデコレーター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')
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
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
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
''' 为了使装饰器不用时能够更好的回收而不是一个一个去注释或者删除 我们引入带参数的装饰器概念 ''' 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
以上がPython デコレータ関数を詳しく見るの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。