Dekorator wywoływany jest tylko raz, natychmiast po zdefiniowaniu funkcji dekorowania. Tak więc, te dwie techniki (przy użyciu @wrap i bar = zawijania (bar)) są takie same:
>>> def wrap(f):
... print 'making arr'
... arr = []
... def inner():
... arr.append(2)
... print arr
... f()
... return inner
...
>>> @wrap
... def foo():
... print 'foo was called'
...
making arr
>>> foo()
[2]
foo was called
>>> foo()
[2, 2]
foo was called
>>> def bar():
... print 'bar was called'
...
>>> bar = wrap(bar)
making arr
>>> bar()
[2]
bar was called
W obydwu przypadkach, oczywiste jest, że ARR powstaje tylko wtedy, gdy okład (F) jest wywoływana i wrap wywoływane tylko wtedy, gdy najpierw deklarowane są foo i bar.
Jeśli chodzi o przekazywanie argumentów do dekorowanej funkcji, pamiętaj, że dekorator przyjmuje jako funkcję parametr i zwraca zmodyfikowaną wersję tej funkcji. Dekorator zazwyczaj przyjmuje jeden parametr, który jest funkcją, którą modyfikuje. Zwraca nową funkcję, a dekorator może zdefiniować zwracaną funkcję jako przyjmującą dowolną liczbę argumentów (na przykład * args). Dekorator może nawet zwrócić funkcję, która ma zbyt wiele parametrów dla dekorowanej metody.
>>> def wrap_with_arg(f):
... def wrap(*args):
... print 'called with %d arguments' % len(args)
... f(args)
... return wrap
...
>>> @wrap_with_arg
... def baz(arg):
... print 'called with argument %r' % arg
...
>>> baz(3)
called with 1 arguments
called with argument 3
>>> baz(3, 4)
called with 2 arguments
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<input>", line 4, in wrap
File "<input>", line 3, in baz
TypeError: not all arguments converted during string formatting
Podczas gdy bazowy generuje błąd, zauważ, że liczba argumentów jest poprawnie wydrukowana zanim zostanie zgłoszony błąd.
+1 wspaniała odpowiedź. –
+1 również, warto wspomnieć, że tworzone jest zamknięcie i dlatego można uzyskać dostęp do 'cache', gdy funkcja' defm' została już zwrócona. – mmarinero
Dziękuję, teraz rozumiem dekoratorów o wiele lepiej! :) –