J'ai tout récemment lutté contre un bug dans Python. C'était une de ces stupides newbie de bugs, mais il m'a fait réfléchir sur les mécanismes de Python (je suis longtemps programmeur C++, Python). Je mettrai sur le code bogué et d'expliquer ce que j'ai fait pour le résoudre, et puis j'ai quelques questions...
Le scénario: j'ai une classe appelée, qui dispose d'un dictionnaire de données des membres, voici son code (c'est la simplification de cours):
class A:
dict1={}
def add_stuff_to_1(self, k, v):
self.dict1[k]=v
def print_stuff(self):
print(self.dict1)
La classe à l'aide de ce code est de catégorie B:
class B:
def do_something_with_a1(self):
a_instance = A()
a_instance.print_stuff()
a_instance.add_stuff_to_1('a', 1)
a_instance.add_stuff_to_1('b', 2)
a_instance.print_stuff()
def do_something_with_a2(self):
a_instance = A()
a_instance.print_stuff()
a_instance.add_stuff_to_1('c', 1)
a_instance.add_stuff_to_1('d', 2)
a_instance.print_stuff()
def do_something_with_a3(self):
a_instance = A()
a_instance.print_stuff()
a_instance.add_stuff_to_1('e', 1)
a_instance.add_stuff_to_1('f', 2)
a_instance.print_stuff()
def __init__(self):
self.do_something_with_a1()
print("---")
self.do_something_with_a2()
print("---")
self.do_something_with_a3()
Notez que chaque appel d' do_something_with_aX()
initialise une nouvelle "propre" de l'instance de la classe A, et imprime le dictionnaire avant et après l'ajout.
Le bug (dans le cas où vous n'avez pas compris encore):
>>> b_instance = B()
{}
{'a': 1, 'b': 2}
---
{'a': 1, 'b': 2}
{'a': 1, 'c': 1, 'b': 2, 'd': 2}
---
{'a': 1, 'c': 1, 'b': 2, 'd': 2}
{'a': 1, 'c': 1, 'b': 2, 'e': 1, 'd': 2, 'f': 2}
Dans la deuxième initialisation de la classe A, les dictionnaires ne sont pas vides, mais commencer avec le contenu de la dernière initialisation, et ainsi de suite. Je m'attendais à démarrer "frais".
Ce qui permet de résoudre ce "bug" est évidemment d'ajouter:
self.dict1 = {}
Dans l' __init__
constructeur de la classe A. Cependant, qui m'a fait me demander:
- Quel est le sens de la "dict1 = {}" initialisation au point de dict1 de la déclaration (première ligne en classe? Il est dénuée de sens?
- Quel est le mécanisme d'instanciation qui provoque la copie de la référence à partir de la dernière initialisation?
- Si j'ajoute "l'auto.dict1 = {}" dans le constructeur (ou tout autre membre de données), comment est-il pas d'incidence sur le dictionnaire membre de déjà initialisé instances?
EDIT: Suivant les réponses que je comprends maintenant que, par la déclaration d'un membre de données et de ne pas s'y référant dans l' __init__
ou quelque part d'autre que soi.dict1, je suis pratiquement la définition de ce qu'on appelle en C++/Java une donnée membre statique. En appelant à soi-même.dict1 je fais "instance"sédentaires".