How to peek inside a decorated function

Peter Otten __peter__ at web.de
Sun Feb 15 04:05:32 EST 2009


Steven D'Aprano wrote:

> Suppose I have a function f() which I know has been decorated, but I don't
> have access to the original undecorated function any longer:
> 
> def reverse(func):
>     def f(*args):
>         args = list(args)
>         args.reverse()
>         return func(*args)
>     return f
> 
> def say(*args):
>     print args
> 
> rsay = reverse(say)
> del say
> 
> 
> Is there any way to peek inside the decorated function rsay() to get
> access to the undecorated function say()?
> 
> If I look at the code object I can see a reference to the original:
> 
>>>> rsay.func_code.co_names
> ('list', 'args', 'reverse', 'func')
> 
> and if I disassemble the code object I can see it being dereferenced:
> 
>>>> dis.dis(rsay.func_code)
> [snip for brevity]
>   5          22 LOAD_DEREF               0 (func)
>              25 LOAD_FAST                0 (args)
>              28 CALL_FUNCTION_VAR        0
>              31 RETURN_VALUE
> 
> but if I look at the closure object, nothing seems useful:
> 
>>>> dir(rsay.func_closure[0])
> ['__class__', '__cmp__', '__delattr__', '__doc__',
> '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__',
> '__reduce_ex__', '__repr__', '__setattr__', '__str__']
> 
> 
> and I can't find any other attributes which refers back to the undecorated
> original function.
> 
> 

Following Terry's lead it turns out that cell contents become easily
accessible in python 2.5:

$ cat cellcontents.py
"""
>>> def reverse(func):
...     def f(*args):
...         args = list(args)
...         args.reverse()
...         return func(*args)
...     return f
...
>>> def say(*args):
...     print args
...
>>> rsay = reverse(say)
>>> del say
>>> c = rsay.func_closure[0]
>>> "cell_contents" in dir(c)
True
>>> c.cell_contents(1,2,3)
(1, 2, 3)
>>>
"""

import doctest
doctest.testmod()
$ python2.6 cellcontents.py
$ python2.5 cellcontents.py
$ python2.4 cellcontents.py
**********************************************************************
File "cellcontents.py", line 15, in __main__
Failed example:
    "cell_contents" in dir(c)
Expected:
    True
Got:
    False
**********************************************************************
File "cellcontents.py", line 17, in __main__
Failed example:
    c.cell_contents(1,2,3)
Exception raised:
    Traceback (most recent call last):
      File "doctest.py", line 1248, in __run
        compileflags, 1) in test.globs
      File "<doctest __main__[6]>", line 1, in ?
        c.cell_contents(1,2,3)
    AttributeError: 'cell' object has no attribute 'cell_contents'
**********************************************************************
1 items had failures:
   2 of   7 in __main__
***Test Failed*** 2 failures.

Peter



More information about the Python-list mailing list