python是否允许从实例方法调用实例变量名称?

时间:2013-07-12 17:24:30

标签: python instance

我想知道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

3 个答案:

答案 0 :(得分:3)

提出异常。它不仅是发出错误信号的合适方式,而且对调试也更有用。回溯包括执行方法调用的行,还包括其他行,行号,函数名等,这些对于调试而言只比变量名更有用。例如:

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和朋友)。

答案 1 :(得分:1)

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)的每个元素,然后finction将其作为实例的名称找到它!

现在,情况更为复杂:

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。

答案 2 :(得分:0)

不,你不能。对象可以有任意数量的名称,因此问题甚至没有意义。考虑:

a1 = a2 = a3 = A()

A()实例的名称是什么?