Python 3.6 文档中的描述符协议示例不正确吗? [英] Is the example of the descriptor protocol in the Python 3.6 documentation incorrect?
问题描述
我是 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 usedinstance.__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屋!