1

在编码过程中,我面临着改变对象属性(但不是类属性)行为的需要。而且我发现已经初始化的对象不能用描述符修补。所以为什么?

代码示例

class A(object):
    pass

class D(object):
    def __init__(self, fget=None, fset=None, fdel=None, doc=None):
        pass
    def __get__(self, obj, objtype=None):
        return 5

A.x = D()
A.x
Out[12]: 5 # work!
a = A()
a.y = D()
a.y
Out[14]: <__main__.D at 0x13a8d90> # not work!
4

1 回答 1

2

文档中。

对于物体来说,机器在object.__getattribute__()其中转化b.xtype(b).__dict__['x'].__get__(b, type(b))

也就是说,对实例( b) 的属性查找转换为对( type(b)) 的描述符调用。描述符在类级别上运行。

至于为什么会这样,这是因为描述符基本上是一种在属性查找上进行类似方法的工作(即调用方法)的方法。方法本质上是类级别的行为:您通常在类上定义您想要的方法,并且您不会向单个实例添加额外的方法。在实例上进行描述符查找就像在实例上定义方法一样。

现在,可以为实例分配新方法,也可以让描述符作用于特定类的实例。你只需要做额外的工作。正如上面的文档引用所说,机器位于 中object.__getattribute__,因此您可以通过在类上定义自定义来覆盖它__getattribute__

class Foo(object):
    def __getattribute__(self, attr):
        myDict = object.__getattribute__(self, '__dict__')
        if attr in myDict and hasattr(myDict[attr], '__get__'):
            return myDict[attr].__get__(self, type(self))
        else:
            return super(Foo, self).__getattribute__(attr)

class D(object):
    def __init__(self, fget=None, fset=None, fdel=None, doc=None):
        pass
    def __get__(self, obj, objtype=None):
        return 5

进而:

>>> f = Foo()
>>> f.x = D()
>>> f.x
5

因此,如果您觉得有必要这样做,您可以实现它。这不是默认行为,仅仅是因为它不是描述符的设计目的。

于 2013-02-25T07:16:35.820 回答