Trình trang trí chỉ được gọi một lần, ngay sau khi hàm trang trí được xác định lần đầu tiên. Như vậy, hai kỹ thuật này (sử dụng @wrap và thanh = bọc (bar)) đều giống nhau:
>>> 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
Trong cả hai trường hợp rõ ràng là arr được tạo ra chỉ khi quấn (f) được gọi, và bọc là chỉ được gọi khi foo và bar được khai báo lần đầu tiên.
Đối với trường hợp chuyển đối số cho hàm được trang trí, hãy nhớ rằng người trang trí cần có một hàm làm thông số và trả về phiên bản đã sửa đổi của hàm đó. Vì vậy, một trang trí thường lấy một tham số, đó là chức năng mà nó đang sửa đổi. Nó trả về một hàm mới, và trình trang trí có thể định nghĩa hàm mà nó trả về khi lấy bất kỳ số đối số nào (ví dụ, * args). Trình trang trí thậm chí có thể trả về một hàm có quá nhiều tham số cho phương thức mà nó trang trí.
>>> 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
Trong khi cuối cùng baz ném lỗi, hãy chú ý số lượng đối số được in chính xác trước khi lỗi được ném.
Nguồn
2012-04-04 12:30:44
+1 câu trả lời tuyệt vời. –
+1 quá, nó sẽ là thú vị để đề cập đến một đóng cửa đang được tạo ra và đó là lý do tại sao nó có thể truy cập 'cache' khi chức năng' defm' đã được trả lại. – mmarinero
Cảm ơn bạn, bây giờ tôi hiểu trang trí tốt hơn nhiều! :) –