Finding closures through introspection

J

John Nagle

I'm doing something with CPython introspection, and I'm trying
to determine whether a function is a closure. Consider

def foo(x) :
global fbar
def bar(y) :
pass
fbar = bar # export closure


foo(0)

We now have "fbar" as a reference to a closure.

"inspect" can tell us some things about foo and fbar:
>>> inspect.getargspec(foo) ArgSpec(args=['x'], varargs=None, keywords=None, defaults=None)
>>> inspect.getargspec(fbar)
ArgSpec(args=['y'], varargs=None, keywords=None, defaults=None)

No difference there.
{'fbar': <function bar at 0x021FD470>,
'__builtins__': <module '__builtin__' (built-in)>,
'inspect': <module 'inspect' from 'C:\python26\lib\inspect.pyc'>,
'm':
[('__call__', <method-wrapper '__call__' of function object at 0x021FD470>),
('__class__', <type 'function'>), ('__closure__', None),
('__code__', <code object bar at 021F1C38, file "<stdin>", line 3>),
('__defaults__', None),
('__delattr__', <method-wrapper '__delattr__' of function object at
0x021FD470>),
('__dict__', {}),
('__doc__', None), ('__format__', <built-in method __format__ of
function object at 0x021FD470>),
('__get__', <method-wrapper '__get__' of function object at 0x021FD470>),
('__getattribute__', <method-wrapper '__getattribute__' of function
object at 0x021FD470>),
('__globals__', {...}),
('__hash__', <method-wrapper '__hash__' of function object at 0x021FD470>),
('__init__', <method-wrapper '__init__' of function object at 0x021FD470>),
('__module__', '__main__'),
('__name__', 'bar'),
('__new__', <built-in method __new__ of type object at 0x1E1FACF0>),
('__reduce__', <built-in method __reduce__ of function object at
0x021FD470>),
('__reduce_ex__', <built-in method __reduce_ex__ of function object at
0x021FD470>),
('__repr__', <method-wrapper '__repr__' of function object at 0x021FD470>),
('__setattr__', <method-wrapper '__setattr__' of function object at
0x021FD470>),
('__sizeof__', <built-in method __sizeof__ of function object at
0x021FD470>),
('__str__', <method-wrapper '__str__' of function object at 0x021FD470>),
('__subclasshook__', <built-in method __subclasshook__ of type object at
0x1E1FACF0>),
('func_closure', None),
('func_code', <code object bar at 021F1C38, file "<stdin>", line 3>),
('func_defaults', None),
('func_dict', {}),
('func_doc', None),
('func_globals', {...}),
('func_name', 'bar')],
'__package__': None, '__name__': '__main__',

No indication there that "fbar" is a closure inside "foo". There
are "__closure__" and "__func_closure__" entries in there, but
they are both None. A non-closure function has the same entries.

So how can I detect a closure?

John Nagle
 
I

Ian Kelly

No indication there that "fbar" is a closure inside "foo".  There
are "__closure__" and "__func_closure__" entries in there, but
they are both None.  A non-closure function has the same entries.

So how can I detect a closure?

Maybe because it has no non-local references, so it's not really a closure?
.... global fbar
.... def bar(y):
.... pass
.... fbar = bar
........ global fbar
.... def bar(y):
.... x
.... fbar = bar
....(<cell at 0x7ffb7dbd8210: int object at 0xa9f2b0>,)

Cheers,
Ian
 
J

John Nagle

I *think* you do it through the co_flags attribute of the code object.
This is in Python 2.5:

although this doesn't seem to be documented, at least not here:

http://docs.python.org/reference/datamodel.html

Got it. Check

f.func_closure

for a non-null value. For a closure, the value will be a Cell object.

The value of "func_closure" in f.func_globals is None, but that's the
wrong place to look, apparently.

John Nagle
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top