デコレーターPythonのすべての使用法を理解するための記事

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クラスを装飾していることがわかります。クラスでデコレータを使用することはあまり一般的ではありませんが、デコレータを実装するプロセスに精通している限り、クラスにデコレータを実装することは難しくありません。上記の例では、デコレータはクラスインスタンスの生成に対する制御を実装するだけです。

インスタンス化プロセス。理解するには、ここで私のデバッグプロセスを参照してください。

705件の元の記事を公開 862を高く評価 150万回以上の訪問+

おすすめ

転載: blog.csdn.net/sinat_38682860/article/details/105455366