我想知道python中是否有一种方法可以调用实例变量的名称?例如,如果我定义一个类
>>>class A(object):
... def get_instance_name(self):
... return # The name of the instance variable
>>>obj = A()
>>>obj.get_instance_name()
obj
>>>blah = A()
>>>blah.get_instance_name()
blah
引发异常。它不仅是发出错误信号的适当方式,而且对于调试也更有用。回溯包括进行方法调用的行,还包括附加的行、行号、函数名等,这些对调试来说比变量名更有用。例子:
class A:
def do(self, x):
if x < 0:
raise ValueError("Negative x")
def wrong(a, x):
a.do(-x)
wrong(A(), 1)
如果未捕获到异常,这将提供与此类似的回溯:
Traceback (most recent call last):
File "...", line 1, in <module>
wrong(A(), 1)
File "...", line 7, in wrong
a.do(-x)
File "...", line 4, in do
raise ValueError("Negative x")
ValueError: Negative x
traceback
即使没有例外(print_stack
和朋友) ,您也可以使用该模块以编程方式获取此信息。
globals()
返回一个表示模块命名空间的字典(命名空间不是这个字典,后者只代表它)
class A(object):
def get_instance_name(self):
for name,ob in globals().iteritems():
if ob is self:
return name
obj = A()
print obj.get_instance_name()
blah = A()
print blah.get_instance_name()
tu = (obj,blah)
print [x.get_instance_name() for x in tu]
结果
obj
blah
['obj', 'blah']
.
考虑到这些言论,我写了这个新代码:
class A(object):
def rondo(self,nameinst,namespace,li,s,seen):
for namea,a in namespace.iteritems():
if a is self:
li.append(nameinst+s+namea)
if namea=='__builtins__':
#this condition prevents the execution to go
# in the following section elif, so that self
# isn't searched among the cascading attributes
# of the builtin objects and the attributes.
# This is to avoid to explore all the big tree
# of builtin objects and their cascading attributes.
# It supposes that every builtin object has not
# received the instance, of which the names are
# searched, as a new attribute. This makes sense.
for bn,b in __builtins__.__dict__.iteritems():
if b is self:
li.append(nameinst+'-'+b)
elif hasattr(a,'__dict__') \
and not any(n+s+namea in seen for n in seen)\
and not any(n+s+namea in li for n in li):
seen.append(nameinst+s+namea)
self.rondo(nameinst+s+namea,a.__dict__,li,'.')
else:
seen.append(nameinst+s+namea)
def get_instance_name(self):
li = []
seen = []
self.rondo('',globals(),li,'')
return li if li else None
与以下
bumbum = A()
blah = A()
print "bumbum's names:\n",bumbum.get_instance_name()
print "\nmap(lambda y:y.get_instance_name(), (bumbum,blah) :\n",map(lambda y:y.get_instance_name(), (bumbum,blah))
print "\n[y.get_instance_name() for y in (bumbum,blah)] :\n",[y.get_instance_name() for y in (bumbum,blah)]
结果是
bumbum's names:
['bumbum']
map(lambda y:y.get_instance_name(), (bumbum,blah) :
[['bumbum'], ['blah']]
[y.get_instance_name() for y in (bumbum,blah)] :
[['bumbum', 'y'], ['blah', 'y']]
第二个列表理解表明函数 get_instance_name() 必须小心使用。在列表 comp 中,标识符y
依次分配给 (bumbum,blah) 的每个元素,然后函数将其作为实例的名称找出来!
.
现在,一个更复杂的情况:
ahah = A() # ahah : first name for this instance
class B(object):
pass
bobo = B()
bobo.x = ahah # bobo.x : second name for ahah
jupiter = bobo.x # jupiter : third name for ahah
class C(object):
def __init__(self):
self.azerty = jupiter # fourth name for ahah
ccc = C()
kkk = ccc.azerty # kkk : fifth name for ahah
bobo.x.inxnum = 1005
bobo.x.inxwhat = kkk # bobo.x.inxwhat : fifth name for ahah
# Since bobo.x is instance ahah, this instruction also
# creates attribute inxwhat in ahah instance's __dict__ .
# Consequently, instance ahah having already 5 names,
# this instruction adds 5 additional names, each one
# ending with .inxwhat
# By the way, this kkk being ahah itself, it results that ahah
# is the value of its own attribute inxwhat.
print ahah.get_instance_name()
结果
['bobo.x', 'bobo.x.inxwhat',
'ahah', 'ahah.inxwhat',
'jupiter', 'jupiter.inxwhat',
'kkk', 'kkk.inxwhat',
'ccc.azerty', 'ccc.azerty.inxwhat']
我同意判断这个解决方案有点重,如果编码人员认为他需要这么重的函数,可能是因为算法不是最优的。但我发现有趣的是,虽然看起来并不明显,但可以在 Python 中执行此操作。
我说沉重,而不是 hacky,顺便说一句,我不觉得它是 hacky。
不,你不能。对象可以有任意数量的名称,所以这个问题甚至没有意义。考虑:
a1 = a2 = a3 = A()
A() 的实例名称是什么?