261 votes

Différence entre les variables à l'intérieur et à l'extérieur de __init__() (attributs de classe et d'instance)

Y a-t-il une différence entre ces classes autre que le nom?

class WithClass ():
    def __init__(self):
        self.value = "Bob"
    def my_func(self):
        print(self.value)

class WithoutClass ():
    value = "Bob"

    def my_func(self):
        print(self.value)

Est-ce que cela fait une différence si j'utilise ou non la méthode __init__ pour déclarer la variable value?

Mon principal souci est que je l'utiliserai d'une certaine manière, ce qui pourrait me causer des problèmes par la suite.

1 votes

Une réponse détaillée avec des exemples dans la question dupliquée : stackoverflow.com/a/9056994/911945

1voto

En Python, une classe est livrée avec fonctions membres (méthodes), variables de classe, attributs/variables d'instance (et probablement aussi des méthodes de classe):

class Employee:

    # Variable de classe
    company = "monentreprise.com"

    def __init__(self, prenom, nom, poste):
        # Variables d'instance
        self._prenom = prenom
        self._nom = nom
        self._poste = poste

    # Fonction membre
    def obtenir_nom_complet(self):
        return f"{self._prenom} {self._nom}"

En créant une instance de l'objet

mon_employe = Employee("Jean", "Lebois", "Ingénieur logiciel")

nous déclenchons essentiellement __init__ qui va initialiser les variables d'instance du nouvel Employé créé. Cela signifie que _prenom, _nom et _poste sont des paramètres explicites de l'instance spécifique _mon_employe_.

De même, les fonctions membres retournent des informations ou modifient l'état d'une instance spécifique.


Maintenant, toute variable définie en dehors du constructeur __init__ est considérée comme une variable de classe. Ces variables sont partagées par toutes les instances de la classe.

jean = Employee("Jean", "Lebois", "Ingénieur logiciel")
bob = Employee("Bob", "Smith", "Ingénieur DevOps")

print(jean.obtenir_nom_complet())
print(bob.obtenir_nom_complet())
print(jean.company)
print(bob.company)

>>> Jean Lebois
>>> Bob Smith
>>> monentreprise.com
>>> monentreprise.com

Vous pouvez également utiliser des méthodes de classe pour modifier la variable de classe pour toutes les instances de la classe. Par exemple :

@classmethod
def changer_nom_de_mon_entreprise(cls, nom):
    cls.company = nom

et maintenant changer_nom_de_mon_entreprise()

bob.changer_nom_de_mon_entreprise("monnouvelleentreprise.com")

aura un effet sur toutes les instances de la classe Employé :

print(bob.company)
print(jean.company)

>>> monnouvelleentreprise.com
>>> monnouvelleentreprise.com

1voto

ntg Points 498

Telle que notée par S.Lott,

Les variables déclarées en dehors de init appartiennent à la classe. Elles sont partagées par toutes les instances.

Les variables créées à l'intérieur de init (et de toutes les autres méthodes) et précédées de self. appartiennent à l'instance de l'objet.

Cependant, Notez que les variables de classe peuvent être accédées via self. jusqu'à ce qu'elles soient masquées par une variable d'objet portant un nom similaire. Cela signifie que lire self. avant de lui assigner une valeur renverra la valeur de Class. mais ensuite il renverra obj.. Voici un exemple

In [20]: class MyClass: 
    ...:     elem = 123 
    ...:  
    ...:     def update(self,i): 
    ...:         self.elem=i  
    ...:     def print(self): 
    ...:         print (MyClass.elem, self.elem) 
    ...:  
    ...: c1 = MyClass()  
    ...: c2 = MyClass() 
    ...: c1.print() 
    ...: c2.print()                                                                                                                                                                                                                                                               
123 123 
123 123 
In [21]: c1.update(1) 
    ...: c2.update(42) 
    ...: c1.print() 
    ...: c2.print()                                                                                                                                                                                                                                                               
123 1 
123 42
In [22]: MyClass.elem=22 
    ...: c1.print()  
    ...: c2.print()                                                                                                                                                                                                                                                               
22 1 
22 42

Deuxième note: Considérez slots. Ils peuvent offrir un moyen meilleur de mettre en œuvre les variables d'objet.

0voto

Ali K. Points 5
class foo(object):
    mStatic = 12

    def __init__(self):
        self.x = "OBj"

En considérant que foo n'a aucun accès à x du tout (FAIT)

le conflit maintenant est d'accéder à mStatic par une instance ou directement par la classe.

pensez-y en termes de gestion de mémoire de Python :

la valeur 12 est en mémoire et le nom mStatic (qui est accessible depuis la classe)

y pointe.

c1, c2 = foo(), foo() 

cette ligne crée deux instances, qui incluent le nom mStatic qui pointe vers la valeur 12 (jusqu'à maintenant).

foo.mStatic = 99 

cela fait que le nom mStatic pointe vers un nouvel emplacement en mémoire qui contient la valeur 99 à l'intérieur.

et parce que les (bébés) c1, c2 suivent toujours le (papa) foo, ils ont le même nom (c1.mStatic et c2.mStatic) pointant vers la même nouvelle valeur.

mais une fois que chaque bébé décide de marcher seul, les choses diffèrent :

c1.mStatic ="c1 Control"
c2.mStatic ="c2 Control"

à partir de maintenant et plus tard, chacun dans cette famille (c1, c2, foo) a son mStatic pointant vers une valeur différente.

[S'il vous plaît, essayez d'utiliser la fonction id() pour tous (c1, c2, foo) dans différents états dont nous avons parlé, je pense que cela rendra les choses meilleures]

et c'est ainsi que se déroule notre vie réelle. Les fils héritent de certaines croyances de leur père et ces croyances restent identiques à celles du père jusqu'à ce que les fils décident de les changer.

ESPOIR QUE CELA AIDERA

0voto

John Friday Points 43

Code d'exemple :

classe à l'intérieur:
    def __init__(self):
        self.l = []

    def insérer(self, élément):
        self.l.append(élément)

classe à l'extérieur:
    l = []                          # variable statique - la même pour toutes les instances

    def insérer(self, élément):
        self.l.append(élément)

def principal():
    x = à l'intérieur()
    x.insérer(8)
    print(x.l)                     # [8]
    y = à l'intérieur()
    print(y.l)                     # []
    # ----------------------------
    x = à l'extérieur()
    x.insérer(8)
    print(x.l)                     # [8]
    y = à l'extérieur()
    print(y.l)                     # [8]           # ici est la différence

si __name__ == '__main__':
    principal()

-1voto

prosti Points 4630

Il est très facile de comprendre si vous suivez les dictionnaires de classe et d'instance.

classe C:
   un = 42
   def __init__(auto,val):
        auto.deux=val
ci=C(50)
print(ci.__dict__)
print(C.__dict__)

Le résultat sera comme suit :

{'deux': 50}
{'__module__': '__main__', 'un': 42, '__init__': , '__dict__': , '__weakref__': , '__doc__': None}

Remarquez que j'ai mis les résultats complets ici, mais ce qui est important, c'est que le dictionnaire de l'instance ci sera juste {'deux': 50}, et le dictionnaire de la classe aura la paire de clés et de valeurs 'un': 42 à l'intérieur.

Voilà tout ce que vous devez savoir sur ces variables spécifiques.

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