Wie die anderen Antworten erklärt haben, Dekorateure weitergegeben werden normalerweise ein einziges implizites Argument Funktion, wenn sie durch nur mit ihren Namen wie folgt aufgerufen:
@deco
def somefunc(...): pass
was dasselbe tut wie:
def somefunc(...): pass
somefunc = deco(somefunc)
Das Argument in dieser Situation ist eine kompilierte Version der Funktionsdefinition, die unmittelbar folgt. In solchen Fällen gibt der Decorator eine Callable zurück, die dem Funktionsnamen anstelle des kompilierten Funktionskörpers zugewiesen wird, wie es normalerweise der Fall wäre.
Wenn jedoch ein Dekorateur Funktion explizit eine gegeben ist oder mehrere Argumente, wenn es aufgerufen wird, wie folgt aus:
@deco(args)
def somefunc(...): pass
Es wird äquivalent zu:
def somefunc(...): pass
somefunc = deco(args)(somefunc)
Wie Sie sehen können, die Dinge in dieser Der Fall funktioniert etwas anders. Die Decorator-Funktion gibt immer noch eine Callable zurück, nur diesmal , die zu einer "normalen" einzelnen impliziten Argument-Dekorator-Funktion erwartet wird, die dann mit einem Funktionsobjekt aus der folgenden Funktionsdefinition wie zuvor aufgerufen wird.
Wieder – als andere haben – darauf hingewiesen, dies macht Dekorateure ausdrücklich Argumente übergeben, Dekorateur Fabriken in dem Sinne, dass sie konstruieren und ‚normale‘ Dekorateur Funktionen zurück.
In den meisten wenn nicht allen Fällen können Decorators entweder als Funktion oder als Klasse implementiert werden, da beide in Python aufgerufen werden können. Ich persönlich finde Funktionen etwas leichter zu verstehen und werde diesen Ansatz im Folgenden verwenden. Auf der anderen Seite kann der Funktionsansatz schwierig werden, da er oft eine oder mehrere verschachtelte Funktionsdefinitionen beinhaltet.
So können Sie einen Dekorator für die Funktion do()
in Ihrem Modul codieren. Im folgenden Code habe ich definiert, was es tut, ist die Argumente der Funktion vor dem Aufruf auszudrucken.
def do(fn, args=tuple(), kwargs={}, priority=0,
block=False, timeout=0, callback=None, daemon=False):
# show arguments
print ('in do(): fn={!r}, args={}, kwargs={}, priority={},\n'
' block={}, timeout={}, callback={}, daemon={}'
.format(fn.__name__, args, kwargs, priority,
block, timeout, callback, daemon))
# and call function 'fn' with its arguments
print (' calling {}({}, {})'.format(
fn.__name__,
', '.join(map(str, args)) if args else '',
', '.join('{}={}'.format(k, v) for k,v in kwargs.items())
if kwargs else '')
)
fn(*args, **kwargs)
def do_decorator(**do_kwargs):
def decorator(fn):
def decorated(*args, **kwargs):
do(fn, args, kwargs, **do_kwargs)
return decorated
return decorator
@do_decorator(priority=2)
def decoratedTask(arg, dic=42):
print 'in decoratedTask(): arg={}, dic={}'.format(arg, dic)
decoratedTask(72, dic=3)
Ausgang:
in do(): fn='decoratedTask', args=(72,), kwargs={'dic': 42}, priority=2,
block=False, timeout=0, callback=None, daemon=False
calling decoratedTask(72, dic=3)
in decoratedTask(): arg=72, dic=3
Hier ist ein Blow-by-Blow-Konto, wie dieses komplizierte suchen Zeug funktioniert:
Die äußere Dekorateur Funktion do_decorator()
, definiert eine andere Innendekorateur-Funktion, die es zurückgibt , hier kreativ genannt decorator
.
Was decorator
tut, ist zu definieren, was zu Funktionen geschieht, die in einem einfachen ‚keine Argumente‘ -Szenario — eingerichtet, die hier definiert, und noch eine weitere – aber letzte – verschachtelte Funktion decorated
genannt Rückkehr, die nur die do()
Funktion des Moduls aufruft und übergibt es sowohl die Argumente, wenn überhaupt von der Stelle des Aufrufs, zusammen mit denen, die für die do()
Funktion vorgesehen sind.
Dieser Anwendungsfall wird durch die Tatsache kompliziert, dass sowohl der äußere Dekorator als auch die zu dekorierenden Funktionen Schlüsselwortargumente haben. Besondere Sorgfalt ist erforderlich, um sicherzustellen, dass die Namen der Schlüsselwörter für jeden Wert eindeutig sind, damit sie nicht in Konflikt stehen (und dass der veränderbare kwargs
-Standardwert für den Argumentwert nicht unbeabsichtigt durch eine Funktion in der Funktion do()
geändert wird).
Dank dieses hat es viel klarer gemacht. Ich werde nur mit tief verschachtelten Funktionsdefinitionen wie dieser verwirrt. Ich bin mir ziemlich sicher, dass ich das verstehe. Lass mich ein bisschen damit spielen, bevor ich das akzeptiere. – Falmarri