Heim > Artikel > Backend-Entwicklung > Detaillierte Erklärung der Python-Dekoratoren
Dekoratoren werden in Python sehr häufig verwendet. Wir können einige spezifische Methoden und allgemeine Methoden als Dekoratoren schreiben. Dies bietet eine große Bequemlichkeit beim Aufrufen dieser Methoden, was die Lesbarkeit, Einfachheit und Skalierbarkeit unseres Codes verbessert.
Bevor wir Python-Dekoratoren lernen, werfen wir einen Blick auf dieses Beispiel:
1. Geltungsbereich
# 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'
Das obige Beispiel gilt einfach für den Geltungsbereich von Python. Hier ist eine Erklärung. Im Beispiel wird die globale Variable msg deklariert, und in der Add-Funktion wird auch eine lokale Variable msg deklariert. Wenn „print msg“ von add() ausgeführt wird, wird zunächst ermittelt, ob in add eine lokale Variable msg vorhanden ist Wenn die Funktion nicht gefunden wird, gehen Sie zu Finden Sie, ob die Variable im oberen Bereich vorhanden ist. Wenn die Funktion endet, werden auch die lokalen Variablen vertieft:
2. Schließung
# coding:utf-8 def add(): msg = 'hello add' def inner(): print msg #运行add()这里会打印'hello add' return inner
>>> obj = add() >>> obj #可见obj是一个指向inner函数的对象 <function inner at 0x0000000002855438> ... >>> obj() hello add #运行obj()打印msg
Wenn Sie nach dem Lesen des obigen Beispiels Zweifel haben, obj ist das Objekt, das auf die innere Funktion zeigt. Wenn obj verwendet wird, entspricht dies der Ausführung von inner, aber die Add-Funktion wird nicht ausgeführt, was bedeutet, dass msg nicht deklariert wird und inner die Variable msg nicht deklariert Finden Sie den Wert der Variablen msg?
Dies ist der „Abschluss“ in Python. In menschlichen Begriffen bedeutet dies, dass Funktionen, die in einem nicht-globalen Bereich verschachtelt sind, sich daran erinnern können, dass sie definiert sind In. Dies kann durch einen Blick auf das obj.func_closure-Attribut der Funktion geschlossen werden. Dieses Attribut enthält den Wert im geschlossenen Bereich (nur der erfasste Wert wird eingeschlossen). Wenn andere Werte in add definiert sind, ist der geschlossene Bereich Nein) Schließung ist das Kernprinzip von Python-Dekoratoren. Als nächstes schreiben wir ein einfaches Dekorator-Beispiel:
3. Einfacher Dekorator
# 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 'The args number is too many!' func(*args_list, **kwargs) return inner @check_args_num def add(x, y): return x + y
Ausführungsergebnisse:
>>>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('The args number is too many!') Exception: The args number is too many! ... >>>add <function inner at 0x0000000002A6C3C8> #可以看到add函数现在指向的是inner
4. Mehrere Dekorateure
# coding:utf-8 def check_args_int(func): # 该装饰器用于检查传入的参数是否是int型 def ensure_int(*args, **kwargs): from array import array try: array('H', 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('The args number is too many!') return func(*args_list, **kwargs) return inner @check_args_num @check_args_int def add(x, y): return x + y
Hier wird ein zusätzlicher Dekorator für die Parameterinhaltsprüfung hinzugefügt. Wenn mehrere Dekoratoren vorhanden sind, wird zuerst Check_args_num und dann check_args_int ausgeführt Sie können sehen, dass add immer noch auf inner verweist. Wenn mehrere Dekoratoren vorhanden sind und add aufgerufen wird, ist der Aufrufeintrag immer der erste Dekorator. Führen Sie dann den nächsten aus und übergeben Sie die Parameter Sequenz
>>> print add(1,'fsaf') 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>5. Dekoratoren mit Parametern Wir wissen, dass bei der Definition eines Dekorators der erste Parameter, der an den Dekorator übergeben wird, die dekorierte Funktion ist (z. B. im Beispiel hinzufügen). Manchmal müssen wir auch zusätzliche Parameter an den Dekorateur übergeben, wie folgt:
# coding:utf-8 def check_args_int(func): # 该装饰器用于检查传入的参数是否是int型 def ensure_int(*args, **kwargs): from array import array try: array('H', args) except Exception, e: raise Exception(e) return func(*args, **kwargs) return ensure_int def check_args_num(flag): ''' :param func: 被装饰函数 :param flag: 决定是否检查参数数量 ''' # 该装饰器用于检查传入的参数数量,检查是否是两个参数 def get_func(func): def inner(*args, **kwargs): if flag == 'false': print 'Skip check !' 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('The args number is too many!') return func(*args_list, **kwargs) return inner return get_func @check_args_num('false') @check_args_int def add(x, y): return x + y
In diesem Beispiel unterscheidet sich nur check_args_num vom vorherigen. Der Unterschied besteht darin, dass der Dekorator check_args_num über ein zusätzliches Parameterflag verfügt. Wenn flag=='false', überspringen Sie die Parameternummernprüfung, das Folgende ist das Ausgabeergebnis 🎜>
>>>print add(1, 2) Skip check ! 3
6. Decorator-Decorator ohne Parameter
Das Decorator-Modul ist ein Python-Modul, das zur spezifischen Kapselung von Decorators verwendet wird Gleichzeitig bleibt die Signatur der dekorierten Funktion erhalten. Zuvor haben wir über die Implementierung der Python-Dekoration durch Verschlüsse gesprochen das Gleiche
from decorator import decorator @decorator def check_num(func, *args, **kwargs): if len(args) != 2: raise Exception('Your args number is not two') else: return func(*args, **kwargs) @check_num def add(x, y): return x + y
>>> add <function add at 0x0000000002D43BA8> >>> print add(1,2) 3 ... >>> 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> TypeError: add() takes exactly 2 arguments (3 given) #可以看到这里当我们传三个参数给add()函数时,他直接从add()函数抛出类型错误异常, #并没有进入check_num装饰器进行参数校验,可见被装饰的函数add()的签名还是他本身 #如果直接构造装饰器,那么这里将会从check_num里面抛出异常,如下: def check_num(func): def inner(*args,**kwargs): if len(args) != 2: raise Exception('Your args number is not two') else: return func(*args,**kwargs) return inner @check_num def add(x, y): return x + y >>> add <function inner at 0x0000000002E233C8> >>>add(1,2,3) Traceback (most recent call last): File "D:\PyCharm 5.0.4\helpers\pydev\pydevd.py", line 2411, in <module> globals = debugger.run(setup['file'], None, None, is_module) File "D:\PyCharm 5.0.4\helpers\pydev\pydevd.py", line 1802, in run launch(file, globals, locals) # execute the script File "E:/code/my_project/decorator/test3.py", line 14, in <module> print add(1,2,3) File "E:/code/my_project/decorator/test3.py", line 4, in inner raise Exception('Your args number is not two') Exception: Your args number is not twoWie aus dem obigen Beispiel ersichtlich ist, erfolgt die Ausführung durch Schließung beim Aufbau eines Dekorators Der Funktionseintrag ist eine verschachtelte Funktion im Dekorator, daher können die oben genannten Probleme auftreten, wenn add(1,2,3) ausgeführt wird, wird die innere Funktion zuerst ausgeführt (wenn im inneren keine Parameterkalibrierung erfolgt). Hier wird keine Ausnahme ausgelöst. Die Funktion add(x,y) wird tatsächlich nur aufgerufen, wenn return func(*args,**kwargs) ausgeführt wird. Nur dann wird eine Ausnahme ausgelöst. Dies führt dazu, dass das Programm redundant ausgeführt wird Code, der Speicher und CPU verschwendet. 7. Dekorator mit Parametern Was ist, wenn der Dekorator Parameter übernehmen soll?
from decorator import decorator def check(flag): @decorator def check_num(func, *args, **kwargs): if flag == 'false': print 'skip check !' return func(*args,**kwargs) if len(args) != 2: raise Exception('Your args number is not two') else: return func(*args, **kwargs) return check_num @check('false') def add(x, y): return x + y >>>add <function add at 0x0000000002C53C18> >>>add(1,2) skip check ! 3Das war’s für das Decorator-Modul, und es gibt einige nicht erwähnte Funktionen, die auf einen Blick sichtbar sind Der Quellcode. Seine Prinzipien werden alle mithilfe von Python-Verschlüssen implementiert 8. functools.wraps(func) decorator Die Funktionen von functools.wraps und decorator-Modulen sind die gleichen, beide zur Lösung des Problems Signaturproblem der dekorierten Funktion, hier listen wir nur ein Beispiel mit Parametern für diese Art von Decorator-Konstruktionsmethode auf:
对比上面通过decorator模块装饰函数的例子,我们可以发现,用decorator装饰函数的代码更加简洁易懂,但是他们二者的执行效率谁更高呢?下面我们通过Timer来测试下:
from timeit import Timer print Timer('add(1,2)',setup='from __main__ import add').timeit(100000) #将该段代码 加在 之前的例子中 #这里打印的是运行100000次的时间
functools.wraps装饰执行结果:
2.37299322602
decorator模块装饰执行结果:
3.42141566059
执行效率wraps略高,但是这里是执行了10万次他们之间的差距约为1秒,所以我个人还是比较青睐于用decorator模块装饰函数,毕竟看起来易懂,写法也较为简单!本文就将装饰器介绍到这里了,当然也没有说尽装饰器的妙用,比如:装饰类...其原理是用类来当做装饰器,类里面需要用到__call__方法,至于装饰类的用法感兴趣的朋友自行百度咯!