ホームページ > バックエンド開発 > Python チュートリアル > Pythonデコレータの詳しい解説

Pythonデコレータの詳しい解説

高洛峰
リリース: 2016-12-01 15:55:17
オリジナル
2315 人が閲覧しました

Python のデコレータは非常に一般的に使用されるもので、いくつかの特定のメソッドと一般的なメソッドをデコレータとして記述することができるため、コードの可読性と簡潔性、およびスケーラビリティが向上します。 。

Python デコレータを学ぶ前に、次の例を見てみましょう:

1. スコープ

1

2

3

4

5

6

7

8

9

10

# coding:utf-8

  

msg = 'hello test1'

  

  

def add():

    msg = 'this is add'

    print msg     #当执行add()时将打印'this is add'

def add2():

    print msg     #当执行add2()时将打印'hello test1'

ログイン後にコピー

上の例では、グローバル変数 msg とローカル変数 msg を宣言しています。 add() の "print msg" が実行されると、まず add にローカル変数 msg があるかどうかを調べます。見つからない場合は、上位レベルのスコープに移動して変数があるかどうかを調べます。ローカル変数は関数の実行時に生成されますが、関数の終了時にローカル変数も破棄されます。 次に、上記の例を詳しく見てみましょう。上の例で、何か注意点はありますか。obj は inner 関数を指すオブジェクトです。obj を実行する場合、inner を実行するのと同じですが、add 関数は実行されません。つまり、msg は宣言されておらず、inner も実行されません。変数 msg を宣言します。変数 msg はどうやって見つけますか?

これはPythonの「クロージャ」です。Pythonは関数クロージャと呼ばれる機能をサポートしています。人間の言葉で言えば、非グローバルスコープにネストされた関数は、それが定義されたときの場所を記憶できます。これは、関数の obj.func_closure 属性を確認することで結論付けることができます。この属性には、閉じられたスコープ内の値が含まれています (キャプチャされた値のみが含まれます。他の値が add で定義されている場合、閉じられたスコープは次のようになります)。いいえ)閉鎖は、Pythonデコレータの中核的な原理です。単純なデコレーターの例:

1

2

3

4

5

6

7

# coding:utf-8

  

def add():

    msg = 'hello add'

    def inner():

        print msg               #运行add()这里会打印'hello add'

    return inner

ログイン後にコピー
-executionsexecution結果:

1

2

3

4

5

6

>>> obj = add()

>>> obj            #可见obj是一个指向inner函数的对象

<function inner at 0x0000000002855438>

...

>>> obj()

hello add           #运行obj()打印msg

ログイン後にコピー

44。

パラメーターの内容をチェックするための追加のデコレーターがここに追加されます。複数のデコレーターがある場合、最初に Check_args_num が実行され、次に check_args_int が実行されます。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

# coding:utf-8

  

def check_args_num(func):

    # 该装饰器用于检查传入的参数数量,检查是否是两个参数

    def inner(*args, **kwargs):

        args_list = list(args)

        if len(args_list) < 2:

  

            for i in range(2 - len(args)):

                # 如果参数数量小于2则用0填补

                args_list.append(0)

        if len(args_list) > 2:

            # 如果参数数量大于2则打印错误

            print &#39;The args number is too many!&#39;

        func(*args_list, **kwargs)

    return inner

  

  

@check_args_num

def add(x, y):

    return x + y

ログイン後にコピー

#Here add が inner を指していることがわかります。複数のデコレータが存在する場合、add が呼び出されるとき、最初のデコレータが実行された後、次のデコレータが実行されます。パラメータは順番に渡されます

5. パラメータを持つデコレータ

デコレータを定義するとき、デコレータに渡される最初のパラメータは装飾された関数 (例: add の例) であることがわかっています。次の例では、デコレータに追加のパラメータを渡す必要もあります。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

>>>print add(1,2)

3

...

>>>print add(100)

100

...

>>>print add(1,2,3)

Traceback (most recent call last):

  File "D:\PyCharm 5.0.4\helpers\pydev\pydevd_exec.py", line 3, in Exec

    exec exp in global_vars, local_vars

  File "<input>", line 1, in <module>

  File "E:/code/my_project/decorator/test1.py", line 14, in inner

    raise Exception(&#39;The args number is too many!&#39;)

Exception: The args number is too many!

...

>>>add

<function inner at 0x0000000002A6C3C8>

#可以看到add函数现在指向的是inner

ログイン後にコピー

この例には、前の例と異なるのは check_args_num だけです。 check_args_num に追加のパラメータフラグがあります。 flag=='false' の場合、パラメータ番号のチェックはスキップされます。 出力結果は次のとおりです

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

# coding:utf-8

  

def check_args_int(func):

    # 该装饰器用于检查传入的参数是否是int型

    def ensure_int(*args, **kwargs):

        from array import array

        try:

            array(&#39;H&#39;, args)

        except Exception, e:

            raise Exception(e)

        return func(*args, **kwargs)

  

    return ensure_int

  

  

def check_args_num(func):

    # 该装饰器用于检查传入的参数数量,检查是否是两个参数

    def inner(*args, **kwargs):

        args_list = list(args)

        if len(args_list) < 2:

  

            for i in range(2 - len(args)):

                # 如果参数数量小于2则用0填补

                args_list.append(0)

        if len(args_list) > 2:

            # 如果参数数量大于2则打印错误

            raise Exception(&#39;The args number is too many!&#39;)

        return func(*args_list, **kwargs)

  

    return inner

  

  

@check_args_num

@check_args_int

def add(x, y):

    return x + y

ログイン後にコピー

6. パラメータのないデコレータ デコレータモジュールは Python A モジュールです。デコレータを具体的にカプセル化するために使用されます。同時に、デコレータを構築するのにデコレータを使用する方が簡単です。 同時に、デコレータ関数のシグネチャは変更されません

ここでは、クロージャを介して Python デコレータ構築を実装することについて説明しました。 Python デコレータとその関数の実装も原理は同じです

1

2

3

4

5

6

7

8

9

10

11

12

13

>>> print add(1,&#39;fsaf&#39;)

Traceback (most recent call last):

  File "D:\PyCharm 5.0.4\helpers\pydev\pydevd_exec.py", line 3, in Exec

    exec exp in global_vars, local_vars

  File "<input>", line 1, in <module>

  File "E:/code/my_project/decorator/test1.py", line 28, in inner

    return func(*args_list, **kwargs)

  File "E:/code/my_project/decorator/test1.py", line 10, in ensure_int

    raise Exception(e)

Exception: an integer is required

...

>>> add

<function inner at 0x0000000002B1C4A8>

ログイン後にコピー

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

# coding:utf-8

  

def check_args_int(func):

    # 该装饰器用于检查传入的参数是否是int型

    def ensure_int(*args, **kwargs):

        from array import array

        try:

            array(&#39;H&#39;, args)

        except Exception, e:

            raise Exception(e)

        return func(*args, **kwargs)

  

    return ensure_int

  

  

def check_args_num(flag):

    &#39;&#39;&#39;

    :param func: 被装饰函数

    :param flag: 决定是否检查参数数量

    &#39;&#39;&#39;

  

    # 该装饰器用于检查传入的参数数量,检查是否是两个参数

    def get_func(func):

  

        def inner(*args, **kwargs):

            if flag == &#39;false&#39;:

                print &#39;Skip check !&#39;

                return func(*args, **kwargs)

            args_list = list(args)

            if len(args_list) < 2:

  

                for i in range(2 - len(args)):

                    # 如果参数数量小于2则用0填补

                    args_list.append(0)

            if len(args_list) > 2:

                # 如果参数数量大于2则打印错误

                raise Exception(&#39;The args number is too many!&#39;)

            return func(*args_list, **kwargs)

  

        return inner

  

    return get_func

  

  

@check_args_num(&#39;false&#39;)

@check_args_int

def add(x, y):

    return x + y

ログイン後にコピー

上の例からわかるように、クロージャを通じてデコレータを構築する場合、その実行関数の入り口はデコレータ内のネストされた関数です。 , したがって、それが発生する可能性があります。上記の問題の場合、add(1,2,3) が実行されると、内側の関数が最初に実行されます (内側でパラメーターの検証がない場合、ここでは例外はスローされません。リターンの場合のみ例外がスローされます)。 func(*args,* が実行されます) *kwargs)、add(x,y) 関数が実際に呼び出され、この時点で例外がスローされます)。これにより、プログラムが冗長なコードを実行し、メモリと CPU を浪費します。

7. パラメータを使用したデコレータ

デコレータにパラメータを取得させたい場合はどうすればよいでしょうか?

1

2

3

>>>print add(1, 2)

Skip check !

3

ログイン後にコピー

このモジュールは比較的単純で、ソース コードを見ることで一目でわかる、言及されていない機能がいくつかあります。原則はすべて Python クロージャを使用して実装されています。 8. functools.wraps( func) デコレータ

functools.wraps とデコレータ モジュールの機能は同じで、どちらもデコレータ関数の署名問題を解決するためのものです。 ここでは、この種のデコレータ構築メソッドのパラメータを使用した例のみを示します。 :

りー


  对比上面通过decorator模块装饰函数的例子,我们可以发现,用decorator装饰函数的代码更加简洁易懂,但是他们二者的执行效率谁更高呢?下面我们通过Timer来测试下:

1

2

3

4

5

6

from timeit import Timer

  

print Timer(&#39;add(1,2)&#39;,setup=&#39;from __main__ import add&#39;).timeit(100000)

  

#将该段代码 加在 之前的例子中

#这里打印的是运行100000次的时间

ログイン後にコピー

  functools.wraps装饰执行结果:

1

2.37299322602

ログイン後にコピー

  decorator模块装饰执行结果:

1

3.42141566059

ログイン後にコピー

   

  执行效率wraps略高,但是这里是执行了10万次他们之间的差距约为1秒,所以我个人还是比较青睐于用decorator模块装饰函数,毕竟看起来易懂,写法也较为简单!本文就将装饰器介绍到这里了,当然也没有说尽装饰器的妙用,比如:装饰类...其原理是用类来当做装饰器,类里面需要用到__call__方法,至于装饰类的用法感兴趣的朋友自行百度咯!

 


関連ラベル:
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
関連するチュートリアル
人気のおすすめ
最新のコース
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート