我正在搜索有关描述符不能为实例变量的基本原理,并发现了此post。在@nneonneo的答案中,他引用了Python邮件列表中的答案。我加了引号here。
答案列出了我有疑问的两个原因:第一个原因是,
如果“ M”描述符是由某些实例而不是由类定义的,则知道对象“ reg”是Register的实例并不能告诉我有关“ reg.M”是有效的属性还是任何信息。一个错误。
但是我的问题是,如果在__init__()
中定义了“ M”描述符,那么 some 实例怎么定义它?初始化后,每个实例都应具有“ M”描述符属性。然后,“ reg.M”应始终为有效属性。
第二个原因,ObjectHolder
示例,
不是将“ holder.obj”视为简单数据 属性,它将开始在访问时调用描述符协议 到“ holder.obj”,并最终将它们重定向到不存在的 没有意义的“ holder.foo”属性,当然不是 该类的作者。
最初的问题是为什么描述符不能是实例变量,第二个原因只是使用现有机制来解释一个假设情况。我的意思是,如果描述符将作为实例变量有效,则应该进行一些检查和转换以使其起作用。我不认为您可以使用“将描述符作为类变量”的机制来解释“将描述符作为实例变量”,特别是后者目前不存在,并且可能会在将来发展为有效。
谢谢
答案 0 :(得分:2)
我对此不够强调:
该行为是设计使然。 [1]
就是这样。这是实现语言的方式,并且为什么装饰器在类中的使用效果更好。您提供的资源详细说明了为什么装饰器在类上可以更好地工作,所以我不再重复。
关于您的问题...
如果在 init ()中定义了“ M”描述符,那么为什么某些实例会定义它?
不是,您是对的。 Ian提出了一个观点,即通常情况下,基于某些条件的每个实例的初始化可能不会等同于“ reg.M”不会引发AttributeError
。类装饰器不是这种情况。如果您总是在__init__
中初始化,那么就可以了。 直到,例如,有人覆盖您的__init__
或对属性执行del
。使用课程,您只需要观看课程即可。
与其将“ holder.obj”视为简单的数据属性,它将开始在访问“ holder.obj”时调用描述符协议,并最终将它们重定向到不存在且毫无意义的“ holder.foo”属性,当然,这不是班级作者的意图。
好吧,我们假设有一个对象:
>>> a = property(lambda o: o.eggs)
>>> a
<property object at 0x7f9db318a838>
这是完全合法的,对吗?好吧,如果我想将其存储在某个类的实例上怎么办?我会的:
>>> class Foo: pass
...
>>> foo = Foo()
>>> foo.a = a
>>> foo.a
<property object at 0x7f9db318a838>
好的,这很酷!
此处实例装饰器的问题在于,如果Python将装饰器协议应用于a
,则不可能实现。键入foo.a
将使其尝试评估eggs
产生AttributeError
。因此,为了具有两种可能的行为,不会在实例foo
上调用装饰器协议。
我希望这可以清除它。 :)
[1] https://mail.python.org/pipermail/python-list/2012-January/618572.html
[2] https://mail.python.org/pipermail/python-list/2012-January/618570.html