Ron_Adam said:
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. .... 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.... def foo(self):
.... x = 'Hello '+'world'
.... for s in varname.object_info(x):
.... print s
....
---------- 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 %s@%s>' % (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)
----------------------------------