python中描述符概念的行为(令人困惑)

时间:2013-06-18 08:27:48

标签: python python-2.7 python-3.x descriptor

我理解python描述符,但我对此有点困惑..

如果你有一个类描述符如下

class Descriptor(object):
    def __get__(self, instance, owner):
        print 'getting'
        return self.value
    def __set__(self, instance, value):
        print 'setting'
        self.value = value
    def __delete__(self, instance):
        print 'deleting'
        del self.value

和我们想要管理其属性的类是这样的..

class Test(object):
    name = Descriptor()
    def __init__(self, name):
        print 'init test'
        self.name = name

当我创建类Test的对象并执行某些操作时,它会给我这样的答案......

t = Test('abc')
init test
setting
>>> t.name
getting 
'abc'
>>> del t.name
deleting
>>> t
<__main__.Test object at 0x013FCCD0>
>>> t.name
getting 

现在我想要一个像这样的类Test1 ..

class Test1(object):
    def __init__(self, value):
        print 'init test1'
        self.name = Descriptor()
        self. value = value

如果我创建Test1的对象并尝试访问Test1实例的属性,我得到类似这样的输出..

t1 = Test1(12)
t1.name
>>> getting
>>> 12
>>> t1.name = 30
>>> setting
问题1)我的问题是这是在Test1的init中声明的这个名称属性,是否绑定到Test1的实例...因为当我尝试获取t1的属性字典时,它返回空字典... < / p>
t1.__dict__
>>> {}

类Test的实例t

 t.__dict__
 >>> {}

当我向这些实例中添加新属性时,就像这样...

 t.some = 'some'
 >>> t1.some = 'some'

再次如果我尝试访问属性字典,它只给我我刚刚添加的内容..现在所有实例属性

t.__dict__
>>> {'some': 'some'}
>>> t1.__dict__
>>> {'some': 'some'}

问2)那么init中定义的实例属性(如变量名和类Descriptor和Test中的值)与实例创建后定义的属性(如变量t.some)之间的区别是什么。

问题3)Class Test如何与Test1类不同。

1 个答案:

答案 0 :(得分:3)

Test1中你的Descriptor并没有真正用作描述符,它只是一个名为name的普通属性,碰巧有一些特殊的方法。但那确实还没有成为一个描述符。

如果read the docs关于如何调用描述符,您将看到用于调用描述符方法的机制。在你的情况下,这意味着t.name大致相当于:

type(t).__dict__['name'].__get__(t, type(t))

t1.name

type(t1).__dict__['name'].__get__(t1, type(t1))

name在类的__dict__中查找,而不是实例,因此差异在于Test1.__dict__没有名为{{1}的描述符}:

name

您还应该考虑的是,您的描述符会在其自身设置>>> Test.__dict__['name'] <__main__.Descriptor object at 0x7f637a57bc90> >>> Test1.__dict__['name'] Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'name' 属性,这意味着value的所有实例将共享相同的值:

Test

我认为您真正想要做的是在>>> t1 = Test(1) init test setting >>> t2 = Test(2) init test setting >>> t1.name getting 2 >>> t2.name getting 2 >>> t1.name = 0 setting >>> t2.name getting 0 上设置value而不是instance,这样可以在self中获得预期的行为。