Python:重载__getattr__和属性,使__setattr__正常工作

时间:2012-09-19 06:46:04

标签: python properties

考虑以下python代码:

class Foo(object):

    def __init__(self, value):
        self._value = value

    @property
    def value(self):
        return "value: {v}".format(v=self._value)

    @value.setter
    def value(self, value):
        self._value = value

class Bar(object):

    def __init__(self):
        self.foo = Foo('foo')

    def __getattr__(self, attr, *args, **kwargs):
        """
        Intercepts attribute calls, and if we don't have it, look at the
        webelement to see if it has the attribute.
        """

        # Check first to see if it looks like a method, if not then just return
        # the attribute the way it is.
        # Note: this has only been tested with variables, and methods.
        if not hasattr(getattr(self.foo, attr), '__call__'):
            return getattr(self.foo, attr)

        def callable(*args, **kwargs):
            '''
            Returns the method from the webelement module if found
            '''
            return getattr(self.foo, attr)(*args, **kwargs)
        return callable

>>> b = Bar()
>>> b.foo
<__main__.Foo object at 0x819410>
>>> b.foo.value
'value: foo'
>>> b.foo.value = '2'
>>> b.foo.value
'value: 2'
>>> b.value
'value: 2'
>>> b.value = '3'
>>> b.value
'3'

最后一部分,我希望它是'value:3'而不是'3',因为现在我的属性'value'现在是一个属性。

是否可能,如果是,我将如何做到这一点。

1 个答案:

答案 0 :(得分:3)

您的__getattr__会返回属性,而不是属性本身。当您访问getattr(self.foo, attr)时,它会相当于self.foo.value并返回该值,并且此时会调用该属性。

因此,您需要实现__setattr__方法,以镜像__getattr__并将值设置传递给包含的foo对象。

在幕后,Python将属性实现为descriptors;他们的__get__() method由较低级别__getattribute__ method调用,这会导致他们返回其计算值。永远不会返回属性对象本身。

以下是__setattr__的例子:

def __setattr__(self, attr, value):
    if hasattr(self, 'foo') and hasattr(self.foo, attr):
        setattr(self.foo, attr, value)
        return
    super(Bar, self).__setattr__(attr, value)

注意:因为您的__init__设置了self.foo,您需要测试您的班级foo是否存在hasattr(self, 'foo')。您还需要调用原始__setattr__实现以确保self.foo = Foo()之类的内容仍然有用。