我正在尝试理解 Python 中的描述符。我似乎无法理解的是描述符方法中的实例和所有者是什么:
object.__get__(self, instance, owner)
现在我已经阅读了文档说:
所有者始终是所有者类,而实例是通过所有者访问属性的实例,或者当通过所有者访问属性时为 None。
不幸的是,我无法理解这意味着什么。所有者是否指类本身?类对象?那么实例传递给它的目的是什么?
我正在尝试理解 Python 中的描述符。我似乎无法理解的是描述符方法中的实例和所有者是什么:
object.__get__(self, instance, owner)
现在我已经阅读了文档说:
所有者始终是所有者类,而实例是通过所有者访问属性的实例,或者当通过所有者访问属性时为 None。
不幸的是,我无法理解这意味着什么。所有者是否指类本身?类对象?那么实例传递给它的目的是什么?
所有者是否指类本身?
是的。
类对象?
这是完全相同的事情。
那么实例传递给它的目的是什么?
描述符如何访问它在 else 上查找的实例?如果以内置property
类型为例,它通过存储访问器函数并回调这些函数来工作。这些函数期望当前实例作为第一个参数(规范命名为“self”)。如果描述符没有得到当前实例,它显然不能将它传递给访问器。
这段代码可以说明这些关系:
class DescriptorClass:
def __get__(self, instance, owner):
return self, instance, owner
class OwnerClass:
descr = DescriptorClass()
ownerinstance = OwnerClass()
self, instance, owner = ownerinstance.descr
assert self is OwnerClass.__dict__['descr']
assert instance is ownerinstance
assert owner is OwnerClass
self, instance, owner = OwnerClass.descr
assert instance is None
考虑这个
__get__(self, instance, owner):
owner
- 这是指创建描述符对象的类,记住描述符对象是在类级别定义的。
instance
- 这是指owner
您定义描述符对象的类的对象。
将 传递instance
给__get__
描述符的方法的目的是确保我们知道并识别owner
您正在从哪个类的对象访问描述符实例。
由于描述符对象是在类级别创建的,因此描述符类本身的简单实现可能会导致类的多个对象owner
覆盖描述符实例的值。这是此类代码的示例
def __get__(self, instance, owner):
return self.data
def __set__(self, instance, data):
if value < 1:
raise Exception("Negative or zero is not allowed")
else:
self.data = value
所以在上面的例子中, 的值仅存储在描述符实例中,如果您正在创建该类的多个对象并且假设这些对象正在设置 的值data
,则此代码将产生严重的副作用。owner
data
因此,为了解决这样的问题,您需要存储data
in __dict__
of的值,instance
但是如果您无法访问instance
描述符类本身,您将如何处理?因此,根据我的经验,这是instance
描述符类的主要目的。作为解决上述问题并投入instance
使用的参考,这里是代码
class DataDescriptor(object):
def __init__(self, attribute):
self.default = 100
self.attribute = attribute
def __get__(self, instance, owner):
print('Getting the value of', self.attribute,
'__get__ of Data descriptor invoked')
return instance.__dict__.get(self.attribute, self.default)
def __set__(self, instance, value=200):
if value > 0:
print('__set__ of Data descriptor invoked')
instance.__dict__[self.attribute] = value
else:
sys.exit('Negative value not allowed')