本文介绍了python中描述符概念的行为(令人困惑)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

类描述符(对象):def __get__(self, instance, owner):打印得到"返回 self.valuedef __set__(self, instance, value):打印设置"self.value = 价值def __delete__(self, instance):打印删除"自我价值

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

类测试(对象):名称 = 描述符()def __init__(self, name):打印初始化测试"self.name = 姓名

当我创建类 Test 的对象并做一些事情时,它给了我这样的答案......

t = Test('abc')初始化测试环境>>>名称得到'ABC'>>>删除名称删除>>>吨<__main__.Test object at 0x013FCCD0>>>>名称得到

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

class Test1(object):def __init__(self, value):打印 'init test1'self.name = Descriptor()自己.价值 = 价值

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

t1 = Test1(12)t1.name>>>得到>>>12>>>t1.name = 30>>>环境

Q 1) 我的问题是这个名称属性是否在 Test1 的 init 中声明,是否绑定到 Test1 的实例...因为当我尝试获取 t1 的属性字典时,它返回空字典...

t1.__dict__>>>{}

类 Test 的实例 t 相同

 t.__dict__>>>{}

当我向这些实例中的任何一个添加新属性时,就像这样...

 t.some = 'some'>>>t1.some = '一些'

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

t.__dict__>>>{'一些':'一些'}>>>t1.__dict__>>>{'一些':'一些'}

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

Q 3) Test 类与 Test1 类有何不同.

解决方案

Test1 中,您的 Descriptor 并没有真正用作描述符,它只是一个名为name,那正好有一些特殊的方法.但这并不能真正使它成为一个描述符.

如果您阅读有关如何调用描述符的文档,您将看到用于调用描述符方法的机制.在您的情况下,这意味着 t.name 将大致相当于:

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

t1.name:

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

name 在类的 __dict__ 中查找,而不是在实例中查找,所以这就是区别所在,Test1.__dict__没有名为 name 的描述符:

>>>测试.__dict__['name']<__main__.Descriptor object at 0x7f637a57bc90>>>>Test1.__dict__['name']回溯(最近一次调用最后一次):文件<stdin>",第 1 行,位于 <module>密钥错误:'名称'

您还应该考虑的是,您的描述符为自身设置了 value 属性,这意味着 Test 的所有实例将共享相同的值:

>>>t1 = 测试(1)初始化测试环境>>>t2 = 测试(2)初始化测试环境>>>t1.name得到2>>>t2.name得到2>>>t1.name = 0环境>>>t2.name得到0

我认为你真正想要做的是在 instance 上设置 value 而不是 self,这会让你得到预期的行为在 Test 中.

I understood python descriptor but I have a little confusion about this..

if you have a class descriptor as follows

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

and a class whose attributes we want to manage is something like this..

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

when I create object of class Test and do something it gives me answer like this...

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

Now I want to have a class Test1 something like this..

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

and if I create object of Test1 and try to access attribute of instance of Test1, I get output something like this..

t1 = Test1(12)
t1.name
>>> getting
>>> 12
>>> t1.name = 30
>>> setting

Q 1) my question is that is this name attribute declared in init of Test1, is bound to instance of Test1 or not... because when I try to get attribute dictionary of t1, it return empty dict...

t1.__dict__
>>> {}

same for class Test's instance t

 t.__dict__
 >>> {}

When I add a new attribute to any of these instances, like this...

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

and again if I try to access attribute dictionary it gives me only which I have added just now.. now all instance attribute

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

Q 2) So what is the difference between instance attributes defined in init (like variable name and value in class Descriptor and Test) and attributes defined after instance creation (like variable t.some).

Q 3) How class Test is different than class Test1.

解决方案

In Test1 your Descriptor isn't really used as a descriptor, it's just a normal attribute called name, that happens to have some the special methods. But that doensn't really make it a descriptor yet.

If you read the docs about how descriptors are invoked, youll see the mechanism that is used to invoke the descriptors methods. In your case this would mean t.name woud be roughly equivalent to:

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

and t1.name:

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

name is looked up in the __dict__ of the class, not of the instance, so that's where the difference is, Test1.__dict__ doesn't have a descriptor called 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'

What you also should consider, is that your descriptor sets the value attribute on itself, that means all instances of Test will share the same value:

>>> 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

I think that what yo acutally want to do is to set value on instance instead of self, that would get you the expected behaviour in Test.

这篇关于python中描述符概念的行为(令人困惑)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-04 23:04