Ron_Adam wrote: > I've been playing around with a way to explore name spaces, but once > you drop into class's, and functions, the references can lead you into > an endless loops. > Here is a rough attempt at printing the names of a variable. It will pick up several names where appropriate, but deliberately doesn't attempt to get all possible names (as you say, that could result in endless loops). In particular, for the Fred=5/John=8/Winner=8 example it will only find one of John or Winner since it only picks at most one match from each dict or list. It doesn't yet manage to correctly lookup attributes (e.g. slots) when they aren't stored in a __dict__, nor does the output distinguish between dictionary keys and values (so encodings.cp437.encoding_map[8] below actually refers to the key not the value).
If you want to track down a memory leak with this code save a weak reference to the variable you expect to be saved and then you may be able to work out why it hasn't been freed later on. I originally wrote a version of this code because I was having problems with xml.dom.ext.reader.HtmlLib (its parser holds onto the DOM from a C extension object which doesn't support garbage collection). In that situation you get variable 'names' beginning with '...' since there is no named variable to start from, but the attributes make it easier to track down which objects are involved and where the circular loops are. Python 2.4 (#60, Nov 30 2004, 11:49:19) [MSC v.1310 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> Fred = 5 >>> John = 8 >>> Winner = John >>> import varname >>> for s in varname.object_info(Winner, False): ... print s ... sre_parse.ESCAPES['\\b'][1] tokenize.tok_name[8] token.tok_name[8] sre_parse.OPCODES['call'] sre_parse.FLAGS['m'] sre_parse.CHCODES['category_loc_word'] sre_parse.ATCODES['at_loc_boundary'] sre_constants.OPCODES['call'] sre_constants.CHCODES['category_loc_word'] sre_constants.ATCODES['at_loc_boundary'] sre_compile.OPCODES['call'] sre_compile.CHCODES['category_loc_word'] sre_compile.ATCODES['at_loc_boundary'] encodings.cp437.encoding_map[8] encodings.cp437.decoding_map[8] encodings.cp1252.encoding_map[8] encodings.cp1252.decoding_map[8] string.expandtabs[0] tokenize.RPAR token.RPAR stat.ST_MTIME sre_parse.SRE_FLAG_MULTILINE sre_constants.SRE_FLAG_MULTILINE sre_compile.SRE_FLAG_MULTILINE sre.M signal.SIGFPE re.M os.O_APPEND nt.O_APPEND inspect.CO_VARKEYWORDS imp.PY_CODERESOURCE gc.DEBUG_INSTANCES __main__.Winner >>> >>> class C: ... def foo(self): ... x = 'Hello '+'world' ... for s in varname.object_info(x): ... print s ... >>> C().foo() __main__.C.foo()x >>> ---------- varname.py ------------ import gc, inspect, types, operator def locate_keyorvalue(obj, container): if isinstance(container, dict): for k, v in container.iteritems(): if v is obj: return 'value', k if k is obj: return 'key', k else: for i, x in enumerate(container): if x is obj: return 'index', i return '???', '' def object_info(obj, anonymous=True): gc.collect() tree = {} ignored = {} def ignore(obj): ignored[id(obj)] = 1 def unignore(obj): del ignored[id(obj)] def safeshow(o): if isinstance(o, (list, dict)): return type(o) return o def buildTree(obj): '''Build a tree of referrers to obj such that tree[id(obj)] -> list of referrers ''' ignore(inspect.currentframe()) objects = [obj] while objects: current = objects.pop() #print "current", type(current), hex(id(current)) if isinstance(current, (types.ModuleType, )): refs = [] # Don't extend references to modules else: refs = [ o for o in gc.get_referrers(current) if not id(o) in ignored ] ignore(refs) tree[id(current)] = refs modules = [ r for r in refs if isinstance(r, (types.ModuleType,)) ] if modules: objects.extend(modules) tree[id(current)] = modules else: # Not yet found a path from a module for r in refs: if not id(r) in tree: objects.append(r) ignore(inspect.currentframe()) ignore(tree) buildTree(obj) def findPath(obj, ignore): '''Find a path from 'obj' back as far as it will go in the tree''' ignore[id(obj)] = 1 referrers = tree[id(obj)] if referrers: for t in referrers: if id(t) in ignore: yield ['...', t, obj] else: for path in findPath(t, ignore): yield path + [obj] else: yield [obj] del ignore[id(obj)] ignores = {} SCORES = { types.ModuleType: 100, type: 70, types.ClassType: 60, types.FrameType: 20, list: 10, dict:10 } results = [] for p in findPath(obj, ignores): score = [] result = [] while p: this = p.pop(0) #print type(this) if hasattr(this, '__dict__') and p[0]==this.__dict__: next = p.pop(0) name = locate_keyorvalue(p[0], next) if not result: result.append(this.__name__) result.append('.') result.append(name[1]) elif isinstance(this, types.FrameType): style, name = locate_keyorvalue(p[0], this.f_locals) code = this.f_code result.append("%s()" % object_info(this.f_code).next()) result.append(name) elif isinstance(this, types.GeneratorType): break else: if isinstance(this, (tuple, list, dict)) and len(p): style, name = locate_keyorvalue(p[0], this) if not result: if not anonymous: break result.append('<anonymous [EMAIL PROTECTED]>' % (type(this).__name__,id(this))) result.append('[%r]' % name) else: if not result: if not anonymous: break result.append('<%s>' % (this,)) #print this break score.append(SCORES.get(type(this), 0)) if result: results.append((score, str.join('', result))) #yield str.join('', result), score result = [] for r in sorted(results, reverse=True): yield r[1] return if __name__=='__main__': def test(): v1 = 'abc'+'def' print "Info for",repr(v1) for s in object_info(v1): print s class Fred(object): __classvar = 'xyzzy1' def foo(self, v): print "Info for", repr(v) for s in object_info(v): print s print myvar = Fred() myvar.abc = 'xyzzy1' pqr = (0, myvar.abc, 1) aDict = {} aDict[myvar.abc] = 'xyzzy1' def test1(x): print "Info for", repr(x) for s in object_info(x, False): print s print test1('xyzzy1') myvar.foo('pqr'+'stu') test() #test1(None) ---------------------------------- -- http://mail.python.org/mailman/listinfo/python-list