[Python-ideas] make __closure__ writable

Yury Selivanov yselivanov.ml at gmail.com
Fri Mar 16 21:58:37 CET 2012


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.  

Again, since the __code__ attribute is modifiable, and __closure__ 
works in tight conjunction with it, I see no point in protecting it.

-
Yury

On 2012-03-16, at 3:24 PM, Mark Shannon wrote:

> Yury Selivanov wrote:
>> On 2012-03-16, at 2:57 PM, Yury Selivanov wrote:
>>> Decorators can be nested, and what you can do in this case is to
>>> find the most inner-wrapped function by traversing the '__wrapped__'
>>> attributes (and check that the function you found is the actual
>>> original function).  After that you can play with its attributes,
>>> but you can't simply substitute the function object, as the inner
>>> decorator won't use it.  So sometimes you have to work with the
>>> function object without a way of substituting it.
>> And that applies to the situations where decorators are not enough
>> and you have to work on the opcode level.
> 
> Which you can do with a decorator.
> 
> Would this do what you want?
> 
> def f_with_new_closure(f, closure):
>    return types.FunctionType(f.__code__,
>                              f.__globals__,
>                              f.__name__,
>                              f.__defaults__,
>                              closure)
> 
> 
> Cheers,
> Mark.
> 
> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> http://mail.python.org/mailman/listinfo/python-ideas




More information about the Python-ideas mailing list