Je suppose que je dois développer cette réponse, maintenant que je suis plus vieux et plus sage et de savoir ce qu'il se passe. Mieux vaut tard que jamais.
Vous pouvez ajouter une propriété à une classe dynamiquement. Mais voilà le hic: vous devez l'ajouter à la classe.
>>> class Foo(object):
... pass
...
>>> foo = Foo()
>>> foo.a = 3
>>> Foo.b = property(lambda self: self.a + 1)
>>> foo.b
4
Un property
est en fait une simple mise en œuvre d'une chose qui s'appelle un descripteur. C'est un objet qui fournit une gestion personnalisée pour un attribut donné, sur une classe donnée. Un peu comme une sorte de facteur énorme if
arbre de __getattribute__
.
Quand je demande, foo.b
dans l'exemple ci-dessus, Python voit que l' b
définie sur la classe implémente le protocole descripteur-ce qui signifie simplement qu'il est un objet avec un __get__
, __set__
ou __delete__
méthode. Le descripteur revendique la responsabilité pour la manipulation de cet attribut, donc Python appels Foo.b.__get__(foo, Foo)
, et la valeur de retour est de nouveau transmis à vous en tant que valeur de l'attribut. Dans le cas d' property
, chacune de ces méthodes se contente d'appeler l' fget
, fset
ou fdel
vous avez passé à l' property
constructeur.
Les descripteurs sont vraiment Python voie d'exposition de la plomberie, de l'ensemble de OO mise en œuvre. En fait, il y a un autre type de descripteur bien plus fréquente qu' property
.
>>> 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>
L'humble méthode est juste un autre type de descripteur. Ses __get__
de punaises sur la convocation de l'instance en tant que premier argument; en effet, il fait ceci:
def __get__(self, instance, owner):
return functools.partial(self.function, instance)
De toute façon, je suppose que c'est pourquoi les descripteurs de travailler uniquement sur les classes: ils sont une formalisation des choses que les pouvoirs de classes dans la première place. Ils sont encore l'exception à la règle: vous pouvez évidemment attribuer des descripteurs à une classe, et les classes sont elles-mêmes des instances de type
! En fait, en essayant de lire en Foo.b
toujours property.__get__
; c'est juste idiomatiques pour les descripteurs de retourner eux-mêmes lors de l'accès comme les attributs de classe.
Je pense que c'est assez cool que la presque totalité de Python OO système peut être exprimée en Python. :)
Oh, et j'ai écrit un long billet de blog sur les descripteurs d'un moment de retour si vous êtes intéressé.