我想我应该扩展这个答案,现在我长大了,更聪明了,知道发生了什么。迟到总比不到好。
可以动态地向类添加属性。但这就是问题所在:你必须把它添加到类中。
>>> class Foo(object):
... pass
...
>>> foo = Foo()
>>> foo.a = 3
>>> Foo.b = property(lambda self: self.a + 1)
>>> foo.b
4
属性实际上是描述符的简单实现。它是一个对象,为给定类的给定属性提供自定义处理。有点像从__getattribute__中分解出一个巨大的if树。
When I ask for foo.b in the example above, Python sees that the b defined on the class implements the descriptor protocol—which just means it's an object with a __get__, __set__, or __delete__ method. The descriptor claims responsibility for handling that attribute, so Python calls Foo.b.__get__(foo, Foo), and the return value is passed back to you as the value of the attribute. In the case of property, each of these methods just calls the fget, fset, or fdel you passed to the property constructor.
描述符实际上是Python暴露其整个OO实现管道的方式。事实上,还有一种比属性更常见的描述符。
>>> class Foo(object):
... def bar(self):
... pass
...
>>> Foo().bar
<bound method Foo.bar of <__main__.Foo object at 0x7f2a439d5dd0>>
>>> Foo().bar.__get__
<method-wrapper '__get__' of instancemethod object at 0x7f2a43a8a5a0>
简单的方法只是另一种描述符。它的__get__将调用实例作为第一个参数;实际上,它是这样做的:
def __get__(self, instance, owner):
return functools.partial(self.function, instance)
不管怎样,我怀疑这就是为什么描述符只在类上起作用:它们是首先为类提供动力的东西的形式化。它们甚至是规则的例外:您可以明显地为类分配描述符,而类本身就是类型的实例!事实上,我试着读Foo。Bar仍然调用property.__get__;描述符在作为类属性访问时返回自己,这只是一种习惯。
我认为几乎所有Python的OO系统都可以用Python来表达,这非常酷。:)
哦,如果你感兴趣的话,我之前写过一篇关于描述符的冗长博文。