2 votes

Pourquoi l'utilisation de self.foo = self.foo dans __init__ dans la classe Python?

Je vois plusieurs fois que les gens écrivent ce qui suit dans leur fonction init.

def __init__(self,**attr):
 self.foo = self.foo

Est-ce un truc (utile) ? Est-ce que quelqu'un peut m'expliquer cela ? Merci.

Mis à jour.

Par exemple, dans graph.py (pour définir la classe Graph) dans networkx Je vois ce qui suit.

def __init__(self, incoming_graph_data=None, **attr):
 self.graph_attr_dict_factory = self.graph_attr_dict_factory
 self.node_dict_factory = self.node_dict_factory

3voto

Grismar Points 2693

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.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X