Avec un peu plus de code, son utilisation peut avoir du sens dans deux cas distincts, bien que ce ne soit pas toujours la meilleure façon d'atteindre ce qu'il réalise:
class MyClass:
baz = 1
def __init__(self):
self.baz = self.baz
self._foo = None
self.bar = None
self.foo = self.foo
@property
def foo(self):
if self._foo is None:
self._foo = 1
return self._foo
@foo.setter
def foo(self, value):
self.bar = 0
self._foo = value
m1 = MyClass()
m2 = MyClass()
print(m1.foo, m1.bar, m1.baz)
m1.baz = 2
MyClass.baz = 3
print(m1.baz, m2.baz, MyClass.baz)
Un peu tiré par les cheveux, mais ce que self.foo = self.foo
réaliserait, c'est que le getter et le setter de la propriété .foo
auraient été appelés.
Les personnes disant que .foo
ne peut pas être accédé à ce stade et déclencherait une AttributeError
ont raison dans le cas limité que vous partagez, mais bien sûr la définition d'une propriété la rend également disponible dans le constructeur, comme le montre l'exemple ici. J'ai gardé le code un peu plus propre en définissant d'abord ._foo
, mais bien sûr vous pourriez simplement le définir d'abord dans le setter, ce qui n'est pas recommandé.
Le fait que les setters et getters soient exécutés est principalement important s'ils ont des effets secondaires, ce qui est une raison d'utiliser des propriétés (une autre raison commune étant que vous souhaitez limiter l'accès ou restreindre les valeurs possibles).
Édition : L'exemple dans networkx
réassigne un attribut de classe à un attribut d'instance (je n'étais pas au courant que cela fonctionnait jusqu'à ce que j'essaie). Voyez le résultat du dernier print()
dans mon exemple :
m1.baz = 2
MyClass.baz = 3
print(m1.baz, m2.baz, MyClass.baz)
Résultat :
2 1 3
La raison pour laquelle networkx
pourrait faire cela est de vous permettre de fournir une méthode de création de graphique différente, sans affecter la classe - seulement votre instance obtiendrait une nouvelle si vous l'assignez à son graph_attr_dict_factory
, mais elle est initialisée avec la méthode de création de la classe.
Cependant, notez que même si networkx
ne l'avait pas configuré de cette manière dans le constructeur, un utilisateur pourrait toujours assigner une nouvelle méthode de création à l'instance ultérieurement et voir le même comportement - la seule vraie différence est que l'instance n'aurait pas eu un attribut d'instance jusqu'à ce point et aurait accédé à l'attribut de classe à la place. Il est possible que d'autres codes reposent sur cette distinction, donc supprimer l'assignation pourrait avoir un impact ailleurs, mais cela ne fait rien pour la fonctionnalité immédiate de la classe elle-même.