Python 3.6 文档中的描述符协议示例不正确吗? [英] Is the example of the descriptor protocol in the Python 3.6 documentation incorrect?

查看:62
本文介绍了Python 3.6 文档中的描述符协议示例不正确吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是 Python 新手,在查看其文档时,我遇到了以下我认为不正确的描述符协议示例..

I am new to Python and looking through its documentation I encountered the following example of the descriptor protocol that in my opinion is incorrect. .

看起来像

class IntField:
    def __get__(self, instance, owner):
        return instance.__dict__[self.name]

    def __set__(self, instance, value):
        if not isinstance(value, int):
            raise ValueError(f'expecting integer in {self.name}')
        instance.__dict__[self.name] = value

    # this is the new initializer:
    def __set_name__(self, owner, name):
        self.name = name

class Model:
    int_field = IntField()

以下是我的考虑.

属性int_field 是一个类范围的属性不是吗?

The attribute int_field is a class-wide attribute is not it?

所以 owner.__dict__ 将拥有这样一个密钥.然而,在方法 __get__ 中使用了没有那个键的 instance.__dict__ .因此,从使用方法的角度来看,该方法不处理类范围的属性,而是处理实例范围的属性.

So owner.__dict__ will have such a key. However in the method __get__ there is used instance.__dict__ that does not have that key. So from the point of view of using the method the method does not deal with the class-wide attribute but deals with an instance-wide attribute.

另一方面,方法__set__也不处理类范围的属性,而是创建一个实例范围的属性,因为有使用

On the other hand, the method __set__ also does not deal with the class-wide attribute but creates an instance-wide attribute because there is used

instance.__dict__[self.name] = value

所以看起来类的每个实例都创建了自己的实例范围属性.此外,对类的引用甚至不会传递给方法.

So it looks like each instance of the class creates its own instance-wide attribute. Moreover a reference to the class even is not passed to the method.

我是对的还是我错过了一些我还不知道的东西?

Am I right or do I have missed something that I do not know yet?

为了使我的考虑更清楚,该示例在逻辑上等同于以下内容

To make my considerations more clear the example logically is equivalent to the following

class MyClass:
    int_field = 10

instance_of = MyClass();

instance_of.__dict__["int_field"] = 20

print( MyClass.int_field )
print( instance_of.int_field )

程序输出为

10
20

实例属性 int_field 除了名称之外与类范围属性 int_field 没有任何共同之处.

The instance attribute int_field has nothing common with the class-wide attribute int_field except its name.

文档中的示例也是如此.直觉上,人们可以预期它是附加到描述符的类范围属性.然而事实并非如此.描述符只是借用了类范围属性的名称.另一方面,类范围的属性确实可以附加到描述符上.

The same is true for the example from the documentation. Intuitively one can expect that it is the class-wide attribute that is attached to the descriptor. However it is not true. The descriptor just borrows the name of the class-wide attribute. On the other hand, a class-wide attribute can indeed be attached to a descriptor.

所以我认为文档中的例子会让读者感到困惑.

So the example from the documentation in my opinion just confuses readers.

推荐答案

这个例子很好.

但是在方法 __get__ 中使用了没有那个键的 instance.__dict__.

However in the method __get__ there is used instance.__dict__ that does not have that key.

一旦你实际设置了instance.int_field,就会有这样一个键,它将调用属性设置器并分配键.

There will be such a key once you actually set instance.int_field, which will invoke the property setter and assign the key.

另一方面,__set__ 方法也不处理类范围的属性,而是创建了一个实例范围的属性

On the other hand, the method __set__ also does not deal with the class-wide attribute but creates an instance-wide attribute

setter 不应该创建类属性.它分配给 getter 正在寻找的实例 dict 键.

The setter isn't supposed to create a class attribute. It assigns to the instance dict key the getter is looking for.

这篇关于Python 3.6 文档中的描述符协议示例不正确吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆