Wenn Sie einen Dekorateur verwenden, ersetzen Sie eine Funktion durch eine andere. Mit anderen Worten, wenn Sie einen Dekorateur haben
def logged(func):
def with_logging(*args, **kwargs):
print(func.__name__ + " was called")
return func(*args, **kwargs)
return with_logging
dann, wenn du sagst
@logged
def f(x):
"""does some math"""
return x + x * x
es ist genau das gleiche wie zu sagen
def f(x):
"""does some math"""
return x + x * x
f = logged(f)
und Ihre Funktion f
wird durch die Funktion ersetzt with_logging
. Leider bedeutet das, wenn Sie dann sagen
print(f.__name__)
Es wird gedruckt, with_logging
da dies der Name Ihrer neuen Funktion ist. Wenn Sie sich die Dokumentzeichenfolge ansehen f
, ist sie leer, da with_logging
sie keine Dokumentzeichenfolge enthält. Daher ist die von Ihnen geschriebene Dokumentzeichenfolge nicht mehr vorhanden. Wenn Sie sich das pydoc-Ergebnis für diese Funktion ansehen, wird es nicht als ein Argument aufgeführt x
. Stattdessen wird es als take aufgeführt *args
und **kwargs
weil with_logging das braucht.
Wenn die Verwendung eines Dekorateurs immer den Verlust dieser Informationen über eine Funktion bedeutete, wäre dies ein ernstes Problem. Deshalb haben wir functools.wraps
. Dies übernimmt eine in einem Dekorateur verwendete Funktion und fügt die Funktionalität zum Kopieren des Funktionsnamens, der Dokumentzeichenfolge, der Argumentliste usw. hinzu. Da wraps
es sich selbst um einen Dekorateur handelt, führt der folgende Code das Richtige aus:
from functools import wraps
def logged(func):
@wraps(func)
def with_logging(*args, **kwargs):
print(func.__name__ + " was called")
return func(*args, **kwargs)
return with_logging
@logged
def f(x):
"""does some math"""
return x + x * x
print(f.__name__) # prints 'f'
print(f.__doc__) # prints 'does some math'