[Python-ideas] make __closure__ writable
Mark Shannon
mark at hotpy.org
Tue Mar 20 15:43:06 CET 2012
Yury Selivanov wrote:
> I did provide such example earlier in this thread. I'm copying and
> pasting it to this mail. Please read the example carefully, as it
> explains why returning new types.FunctionType() is not enough.
>
> ----
>
> Yes, your approach will work if your decorator is the only one applied.
> But, as I said, if you have many of them (see below), you can't just
> return a new function out of your decorator, you need to change the
> underlying "in-place". Consider the following:
>
> def modifier(func):
> orig_func = func
>
> while func.__wrapped__:
> func = func.__wrapped__
>
> # patch func.__code__ and func.__closure__
> return orig_func # no need to wrap anything
>
> def some_decorator(func):
> def wrapper(*args, **kwargs):
> # some code
> return func(*args, **kwargs)
> functools.wraps(wrapper, func)
> return wrapper
>
> @modifier
> @some_decorator
> def foo():
> # this code needs to be verified/augmented/etc
>
> So, in the above snippet, if you don't want to discard the
> @some_decorator by returning a new function object, you need to modify
> the 'foo' from the @modifier.
>
> In a complex framework, where you can't guarantee that your magic
> decorator will always be called first, rewriting the __closure__
> attribute is the only way.
So why won't this work?
def f_with_new_closure(f, closure):
return types.FunctionType(f.__code__,
f.__globals__,
f.__name__,
f.__defaults__,
closure)
def modifier(func, closure):
if func.__wrapped__:
while func.__wrapped__.__wrapped__:
func = func.__wrapped__
func.__wrapped__ = f_with_new_closure(func.__wrapped__,
closure)
else:
return f_with_new_closure(func, closure)
if func.__wrapped__:
return f_with_new_closure(func,
f_with_new_closure(func.__wrapped__))
else:
return f_with_new_closure(func, closure)
Cheers,
Mark.
More information about the Python-ideas
mailing list