访问__setattr__中的对象属性

时间:2013-08-13 08:31:31

标签: python

Python今天咬了我一下。我正试图在其__setattr__实现中访问对象的属性 - 我无法弄清楚如何。这是我到目前为止所尝试的:

class Test1(object):
    def __init__(self):
        self.blub = 'hi1'

    def __setattr__(self, name, value):
        print self.blub

class Test2(object):
    def __init__(self):
        self.blub = 'hi2'

    def __setattr__(self, name, value):
        print object.__getattr__(self, 'blub')

class Test3(object):
    def __init__(self):
        self.blub = 'hi3'

    def __setattr__(self, name, value):
        print object.__getattribute__(self, 'blub')

class Test4(object):
    def __init__(self):
        self.blub = 'hi4'

    def __setattr__(self, name, value):
        print self.__getattr__('blub')

class Test5(object):
    def __init__(self):
        self.blub = 'hi5'

    def __setattr__(self, name, value):
        print self.__getattribute__('blub')

class Test6(object):
    def __init__(self):
        self.blub = 'hi6'

    def __setattr__(self, name, value):
        print self.__dict__['blub']

测试:

try:
    TestX().bip = 'bap'
except Exception as ex:
    print ex

X16

输出:

'Test1' object has no attribute 'blub'
type object 'object' has no attribute '__getattr__'
'Test3' object has no attribute 'blub'
'Test4' object has no attribute '__getattr__'
'Test5' object has no attribute 'blub'
'blub'

有什么建议吗?

5 个答案:

答案 0 :(得分:4)

因为在__init__内部,它试图设置调用blub的{​​{1}};它没有设置任何东西,只是试图访问(和打印)__setattr__,什么也没找到并引发错误。检查一下:

blub

答案 1 :(得分:2)

OP,你还没告诉我们整个故事。你不只是运行这样的代码:

TestX().bip = 'bap'

您运行的代码如下:

try:
    TestX().bip = 'bap'
except Exception as ex:
    print ex

有很大的不同。你为什么问?好吧,您的输出似乎乍一看表示Test6有效,并且有几条评论和答案假定它确实有效。为什么它似乎有用?阅读代码,无法它应该工作。仔细检查源代码会发现,如果 有效,它应该打印hi6,而不是'blub'

我在print ex的{​​{1}}行放置一个断点来检查异常:

pdb

出于某种原因,(Pdb) ex KeyError('blub',) (Pdb) print ex 'blub' 不会像您期望的那样打印print ex,而只是KeyError: blub,这就是'blub'似乎有用的原因。

所以我们已经清除了这一点。将来,请不要遗漏这样的代码,因为它可能很重要。

所有其他答案都正确地指出您尚未设置您尝试打印的属性,这是您的问题。在您接受此答案之前,您之前接受的答案仍然是,规定了以下解决方案:

Test6

虽然这个解决方案确实有效,但它并不是一个好的设计。这是因为您可能希望在某个时刻更改基类,并且该基类在设置和/或获取属性时可能会产生重要的副作用,或者它可能根本不会将属性存储在def __setattr__(self, name, value): self.__dict__[name] = value print self.__dict__[name] 中!更好的设计是为了避免弄乱self.__dict__

正确的解决方案是调用父__dict__方法,这是由至少一个其他答案建议的,尽管python 2.x的语法错误。我就是这样做的:

__setattr__

如您所见,我正在使用def __setattr__(self, name, value): super(Test6, self).__setattr__(name, value) print getattr(self, name) 代替getattr来动态查找属性。与直接使用__dict__不同,这会在适当时调用__dict__self.__getattr__

答案 2 :(得分:1)

print self.__dict__['blub']

打印出blub这是正确的。你必须先设置新值,因为python不会那样做,就像那样:

def __setattr__(self, name, value):
    self.__dict__[name] = value
    print self.__dict__[name]

然后test6.blub = 'test'应打印出test

修改

根据@Lauritz的建议,您也可以使用

def __setattr__(self, name, value):
    super(Test6, self).__setattr__(name, value)
    print self.__dict__[name]

调用父函数,所以如果你的超类已经有__setattr__函数,它就不会被覆盖。

答案 3 :(得分:1)

您实际上从未在__setattr__中设置属性,因此对象当然没有。

def __setattr__(self, name, value):
    self.name = value
        # this doesn't work, since it calls itself (the __setattr__)

def __setattr__(self, name, value):
    super().__setattr__(name, value)
        # call the default implementation directly in Py 3.x

def __setattr__(self, name, value):
    super(TestX, self).__setattr__(name, value) # for Python 2.x

当然,单独做这件事是没有用的,你通常想要添加一些功能,如某些条件,调试打印,缓存或任何你需要的。

答案 4 :(得分:1)

__setattr__适用于课程,所以当你超越时 - 你需要让它实际设置属性......否则,它永远不会存在..例如:

object.__setattr__(self, name, value)

所以,在你的__init__中,当你self.blub = 'hi'实际上是一个无操作时。