01.デコレータ構文糖
長い間Pythonを使用している場合は、@記号に精通している必要がありますはい、@記号はデコレータの構文糖衣です。
関数が定義され始めた場所に配置され、この関数の頭に帽子のように着用されます。この関数にバインドします。この関数を呼び出すとき、最初にこの関数を実行するのではなく、頭の上の帽子にこの関数をパラメーターとして渡します。この帽子は装飾関数または装飾子と呼ばれます。
あなたは私にデコレータが達成できる機能を尋ねなければなりませんか?デコレータはあなたの脳と同じくらい強力です。
デコレータの使用方法は非常に固定されています。
最初に装飾的な関数(帽子)を定義します(クラスと部分関数で実装することもできます)
- 次に、ビジネス関数またはクラス(人)を定義します
- 最後にこの帽子をこの人の頭につけます
デコレータには多くの単純な用途がありますが、ここでは2つの一般的な用途を示します。
- ログプリンター
- タイムタイマー
02.使用の開始:ログプリンター##
1つ目はログプリンターです。
実現される機能:
関数を実行する前に、まずログを出力して、関数を実行することをホストに通知します。
関数が実行された後は、お尻を撫でて離れることはできませんが、丁寧なコードがあり、ログを1行出力してホストに通知しました。これで終了です。
# 这是装饰函数
def logger(func):
def wrapper(*args, **kw):
print('我准备开始计算:{} 函数了:'.format(func.__name__))
# 真正执行的是这行。
func(*args, **kw)
print('啊哈,我计算完啦。给自己加个鸡腿!!')
return wrapper
私のビジネス機能が2つの数値の合計を計算することである場合。書き終えたら、帽子を直接かぶせます。
@logger
def add(x, y):
print('{} + {} = {}'.format(x, y, x+y))
次に計算してみましょう。
add(200, 50)
何が出力されるか見て、それは魔法ですか?
計算を開始する準備ができました:関数を追加:
200 + 50 = 250
ああ、終わりました。ドラムスティックを追加してください!
03.使用の開始:時間タイマー##
時間タイマー
実装関数を見てみましょう。名前が示すように、関数の実行時間を計算することです。
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
# 这是装饰函数
def timer(func):
def wrapper(*args, **kw):
t1=time.time()
# 这是函数真正执行的地方
func(*args, **kw)
t2=time.time()
# 计算下时长
cost_time = t2-t1
print("花费时间:{}秒".format(cost_time))
return wrapper
私たちの機能が10秒間スリープすることだとします。このようにして、計算時間が信頼できるかどうかをよりよく確認できます。
import time
@timer
def want_sleep(sleep_time):
time.sleep(sleep_time)
want_sleep(10)
見て、出力してください。本当に10秒です。本当に悪い!!!
花费时间:10.0073800086975098秒
04.高度な使用法:パラメーター付きの関数デコレーター##
上記の簡単な紹介を通して、おそらくすでに装飾の魔法の魅力を感じているでしょう。
ただし、デコレータの使用はこれをはるかに超えています。この点について本日明らかにします。
上記の例では、デコレータはパラメータを受け入れることができません。その使用法は、いくつかの単純なシナリオにのみ適用できます。パラメーターを渡さないデコレーターは、修飾された関数に対して固定ロジックのみを実行できます。
経験がある場合は、プロジェクトに頻繁に参加し、パラメーターを持ついくつかのデコレーターを確認する必要があります。
デコレータ自体は関数であり、関数として運ぶことができないため、この関数の機能は非常に制限されています。実行できるのは固定ロジックのみです。これは間違いなく非常に不合理です。また、2つのコンテンツをほぼ同じにしたい場合、場所によってはロジックが異なるだけです。パラメータを渡さない場合は、2つのデコレータを作成します。Xiao Mingは耐えられないと感じました。
したがって、デコレータはパラメータの受け渡しをどのように実装するのでしょうか。それはより複雑になり、2つのレベルのネストが必要になります。
同様に、例を見てみましょう。
これらの2つの関数を実行すると、国籍に基づいて挨拶します。
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
def american():
print("我来自中国。")
def chinese():
print("I am from America.")
2人にデコレーターを置くときは、デコレーターにその国が誰であるかを伝える必要があります。そうすれば、デコレーターが判断して挨拶します。
帽子をかぶった後の様子です。
@say_hello("china")
def american():
print("我来自中国。")
@say_hello("america")
def chinese():
print("I am from America.")
すべてが準備できました。帽子だけです。ここで、2つのレベルのネストが必要です。
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
def say_hello(contry):
def wrapper(func):
def deco(*args, **kwargs):
if contry == "china":
print("你好!")
elif contry == "america":
print('hello.')
else:
return
# 真正执行函数的地方
func(*args, **kwargs)
return deco
return wrapper
やる
american()
print("------------")
chinese()
出力を見てください。
你好!
我来自中国。
------------
hello.
I am from America
うーん、これは非常にNBです。。。
05.高度な使用法:パラメータなしのクラスデコレータ##
上記はすべて関数に基づくデコレータですが、他の人のコードを読むと、クラスに基づくデコレータもあることがよくあります。
クラスデコレータの実装に基づいて、2つの組み込み関数__ call__および__ init__を実装する必要があります。
__ init__:デコレートされた関数の受信
__ call__:デコレーションロジックを実装します。
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
class logger(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("[INFO]: the function {func}() is running..."\
.format(func=self.func.__name__))
return self.func(*args, **kwargs)
@logger
def say(something):
print("say {}!".format(something))
say("hello")
実行して出力を確認してください
[INFO]: the function say() is running...
say hello!
06.高度な使用法:パラメータを使用したクラスデコレータ##
上記のパラメータなしの例では、INFOレベルのログしか印刷できません。通常の状況では、DEBUG WARNINGおよびその他のレベルのログも印刷する必要があります。これには、クラスデコレータにパラメータを渡し、この関数にレベルを割り当てる必要があります。
パラメータがある場合とない場合のクラスデコレータは大きく異なります。
__ init__:デコレートされた関数を受け取りませんが、着信パラメーターを受け取ります。
__ call__:デコレートされた関数を受け取り、デコレーションロジックを実装します。
class logger(object):
def __init__(self, level='INFO'):
self.level = level
def __call__(self, func): # 接受函数
def wrapper(*args, **kwargs):
print("[{level}]: the function {func}() is running..."\
.format(level=self.level, func=func.__name__))
func(*args, **kwargs)
return wrapper #返回函数
@logger(level='WARNING')
def say(something):
print("say {}!".format(something))
say("hello")
WARNINGレベルを指定して実行し、出力を確認します。
[WARNING]: the function say() is running...
say hello!
07.部分的な関数とクラスを使用してデコレーターを実装する##
ほとんどのデコレータは関数とクロージャに基づいて実装されていますが、これがデコレータを作成する唯一の方法ではありません。
実際、Pythonには、デコレータ(@decorator)の形式でオブジェクトを使用できるかどうかの要件が1つだけあります。デコレータは「呼び出し可能な」オブジェクトでなければなりません。
この呼び出し可能オブジェクトについては、関数に最も精通しています。
関数に加えて、クラスは呼び出し可能オブジェクトにすることもできます。__call__関数が実装されている限り(上記のボックスは触れられています)、人がめったに使用しない部分的な関数もあります。
次に、クラスと部分関数を使用して独特のデコレーターを実現する方法について説明します。
以下に示すように、DelayFuncは__call__を実装するクラスであり、delayはデコレータとして使用できる部分的な関数を返します。(次のコードは、Pythonの職人から取得したものです:デコレーターを使用するためのヒント)
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
import time
import functools
class DelayFunc:
def __init__(self, duration, func):
self.duration = duration
self.func = func
def __call__(self, *args, **kwargs):
print(f'Wait for {self.duration} seconds...')
time.sleep(self.duration)
return self.func(*args, **kwargs)
def eager_call(self, *args, **kwargs):
print('Call without delay')
return self.func(*args, **kwargs)
def delay(duration):
"""
装饰器:推迟某个函数的执行。
同时提供 .eager_call 方法立即执行
"""
# 此处为了避免定义额外函数,
# 直接使用 functools.partial 帮助构造 DelayFunc 实例
return functools.partial(DelayFunc, duration)
私たちのビジネス機能は非常に簡単です、追加するだけです
@delay(duration=2)
def add(a, b):
return a+b
実装プロセスを見てください
>>> add # 可见 add 变成了 Delay 的实例
<__main__.DelayFunc object at 0x107bd0be0>
>>>
>>> add(3,5) # 直接调用实例,进入 __call__
Wait for 2 seconds...
8
>>>
>>> add.func # 实现实例方法
<function add at 0x107bef1e0>
08.デコレーションできるデコレータの書き方は?##
Pythonでシングルトンパターンを記述する場合、一般的な3つの記述方法があります。それらの1つは、デコレーターで実装されます。
以下は、私が書いたデコレータバージョンの1つのケースです。
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
instances = {}
def singleton(cls):
def get_instance(*args, **kw):
cls_name = cls.__name__
print('===== 1 ====')
if not cls_name in instances:
print('===== 2 ====')
instance = cls(*args, **kw)
instances[cls_name] = instance
return instances[cls_name]
return get_instance
@singleton
class User:
_instance = None
def __init__(self, name):
print('===== 3 ====')
self.name = name
シングルトン装飾関数を使用してUserクラスを装飾していることがわかります。クラスでデコレータを使用することはあまり一般的ではありませんが、デコレータを実装するプロセスに精通している限り、クラスにデコレータを実装することは難しくありません。上記の例では、デコレータはクラスインスタンスの生成に対する制御を実装するだけです。
インスタンス化プロセス。理解するには、ここで私のデバッグプロセスを参照してください。