Finding objects' names
Every now and then, Python newbies get into a situation where they think they need to know the “name” of an object, i.e. the name it is bound to. The canonical answer is that there is no such thing as a one-on-one mapping of objects and names; an object doesn’t need a name to be alive, only a reference to it, and a name can refer to many objects, depending which namespace you look at.
Still, Python’s introspection capabilities are powerful enough that it is possible to find out what names an object is bound to, which this snippet shows:
This prints [’foo’, ‘bar’].
The second part of the find_names function is straightforward once you know about the gc module; Python’s GC implementation makes it possible to query for all objects that refer (own a reference to) another object. This can be used to find all namespaces (which are just Python dictionaries) that reference our given object.
The first part is trickier: if you leave out the first three lines of the function, you will only get [’foo’] as the script’s output. It seems that there is no dictionary with “bar” referring to our object. What happens there?
Well, since the names of all locals are known at compile-time, Python “optimizes” function locals, putting them into an array instead of a dictionary, which speeds up access tremendously. But there is a way to get at the locals in a dictionary, namely the locals() function. There must be some way to get Python to create it for us! This is best done accessing the frame object’s f_locals attribute which creates and caches this dictionary, and that can be used to create dict references to all locals if the whole chain of currently executed frames is traversed, as the first for loop does.
Not that this function is useful for anything ;-)
Still, Python’s introspection capabilities are powerful enough that it is possible to find out what names an object is bound to, which this snippet shows:
import gc, sys def find_names(obj): frame = sys._getframe() for frame in iter(lambda: frame.f_back, None): frame.f_locals result = [] for referrer in gc.get_referrers(obj): if isinstance(referrer, dict): for k, v in referrer.iteritems(): if v is obj: result.append(k) return result foo = [] def demo(): bar = foo print find_names(bar) demo()
The second part of the find_names function is straightforward once you know about the gc module; Python’s GC implementation makes it possible to query for all objects that refer (own a reference to) another object. This can be used to find all namespaces (which are just Python dictionaries) that reference our given object.
The first part is trickier: if you leave out the first three lines of the function, you will only get [’foo’] as the script’s output. It seems that there is no dictionary with “bar” referring to our object. What happens there?
Well, since the names of all locals are known at compile-time, Python “optimizes” function locals, putting them into an array instead of a dictionary, which speeds up access tremendously. But there is a way to get at the locals in a dictionary, namely the locals() function. There must be some way to get Python to create it for us! This is best done accessing the frame object’s f_locals attribute which creates and caches this dictionary, and that can be used to create dict references to all locals if the whole chain of currently executed frames is traversed, as the first for loop does.
Not that this function is useful for anything ;-)
- Paddy.
— Paddy3118 on Saturday, May 30, 2009 15:56 #
— rgz on Saturday, May 30, 2009 19:00 #
Getting-carried-away'ly
Benjamin
— Benjamin on Tuesday, June 2, 2009 1:54 #
bitten by the snake
— abki on Monday, June 22, 2009 1:51 #
— Mariana Soffer on Monday, June 22, 2009 4:10 #
Don't feed the troll, plz... everybody know that pickle is a fool letter word.
— abki on Monday, June 22, 2009 5:20 #
Nice. I’ve been trying to figure out if this is doable for some time. All the forums say no\don’t try. Not that I have a use for it either, but I like the mystery solved.
— Eric Pavey on Friday, January 8, 2010 19:02 #