为什么在__init__函数中声明描述符类会破坏描述符功能?

10 投票
3 回答
2322 浏览
提问于 2025-04-15 12:17

在下面的B类中,我希望每当给().a赋值时,能够调用A类中的__set__函数。然而,实际上给().a赋值时,它只是直接用新值覆盖了().a。而C类中的().a赋值是正常工作的,但我希望每个用户类都有一个独立的A类实例,也就是说,我不希望在一个C()实例中改变'a'会影响到其他所有实例。我写了一些测试来帮助说明这个问题。你能帮我定义一个类,使得它能通过test1和test2这两个测试吗?

class A(object):
    def __set__(self, instance, value):
        print "__set__ called: ", value

class B(object):
    def __init__(self):
        self.a = A()

class C(object):
    a = A()

def test1( class_in ):
    o = class_in()
    o.a = "test"
    if isinstance(o.a, A):
        print "pass"
    else:
        print "fail"

def test2( class_in ):
    o1, o2 = class_in(), class_in()
    if o1.a is o2.a:
        print "fail"
    else:
        print "pass"

3 个回答

0

我遇到了一个类似的问题,我想用一个描述符来管理对象的属性。结果我发现,这些属性在所有对象中都被覆盖了,导致它们不再是独立的。

我在StackOverflow上提了个问题,得到的答案可以在这里找到:类属性无缘无故改变值

关于描述符的一个很好的文档链接在这里:http://martyalchin.com/2007/nov/24/python-descriptors-part-2-of-2/

下面是来自上述链接的一个描述符示例:

class Numberise(object):
    def __init__(self, name):
        self.name = name

    def __get__(self, instance, owner):
        if self.name not in instance.__dict__:
            raise (AttributeError, self.name)
        return '%o'%(instance.__dict__[self.name])

    def __set__(self, instance, value):
        print ('setting value to: %d'%value)
        instance.__dict__[self.name] = value
0

这里有一个类,它可以通过最初的测试,但在大多数情况下不要尝试使用它。因为它在检查自己类型的时候会失败!

class E(object):
    def __new__(cls, state):
        class E(object):
            a = A(state)
            def __init__(self, state):
                self.state = state
        return E(state)

#>>> isinstance(E(1), E)
#False
5

根据文档的说明:

以下方法仅适用于当包含该方法的类的实例(也就是所谓的描述符类)出现在另一个新式类的类字典中,这个新式类被称为拥有类。在下面的例子中,“属性”指的是拥有类的__dict__中,属性名称对应的键。描述符只能作为新式类本身来实现。

所以,你不能在实例上使用描述符。

不过,由于描述符可以获取到用于访问它的实例的引用,你可以把这个实例作为存储状态的关键,这样就可以根据不同的实例实现不同的行为。

撰写回答