
On 2012-03-20, at 10:56 AM, Yury Selivanov wrote:
Because usually you write decorators as functions, not classes. And when you do the former style, you usually do it in the following way:
def decorator(func): def wrapper(*args, **kwargs): return func(*args, **kwargs)
functools.wraps(wrapper, func) return wrapper
Now, let's use it:
@decorator def some_func(): pass
OK. At this point, 'some_func' object has a '__wrapped__' attribute, that points to original 'some_func' function. But whatever you write to 'some_func.__wrapped__' won't change anything, as the 'wrapper' will continue to call old 'some_func'. Instead of assigning something to __wrapped__, we need to change it in-place, by doing '__wrapped__.__closure__ = new_closure'.
And as I told you in the first example: there is no problem when you have only one decorator. You can surely just return a new FunctionType(). But when you have many of them, such as: @decorator3 @your_magic_decorator_that_modifies_the_closure @decorator2 @decorator1 def some_func(): pass The only way to modify the __closure__ it to write to the __wrapped__ attribute of 'decorator1' wrapper. - Yury