web-dev-qa-db-fra.com

python variables d'instance de classe et variables de classe

J'ai un problème pour comprendre comment les variables de classe/instance fonctionnent en Python. Je ne comprends pas pourquoi lorsque j'essaie ce code, la variable de liste semble être une variable de classe

class testClass():
    list = []
    def __init__(self):
        self.list.append('thing')

p = testClass()
print p.list

f = testClass()
print f.list

Production:

['thing']
['thing', 'thing']

et quand je fais cela, il semble être une variable d'instance

class testClass():
    def __init__(self):
        self.list = []
        self.list.append('thing')

p = testClass()
print p.list

f = testClass()
print f.list

Production:

['thing']
['thing']
29
jonathan topf

Cela est dû à la façon dont Python résout les noms avec le .. Lorsque vous écrivez self.list le Python essaie de résoudre le nom list d'abord en le recherchant dans l'objet instance, et s'il n'y est pas trouvé, puis dans l'instance de classe.

Examinons-le pas à pas

self.list.append(1)
  1. Y a-t-il un nom list dans l'objet self?
    • Oui: utilisez-le! Terminer.
    • Non: passez à 2.
  2. Y a-t-il un nom list dans l'instance de classe de l'objet self?
    • Oui: utilisez-le! terminer
    • Pas d'erreur!

Mais lorsque vous liez un nom, les choses sont différentes:

self.list = []
  1. Y a-t-il un nom list dans l'objet self?
    • Oui: remplacez-le!
    • Non: Liez-le!

Donc, c'est toujours une variable d'instance.

Votre premier exemple crée un list dans l'instance de classe, car il s'agit de la portée active à l'époque (pas de self n'importe où). Mais votre deuxième exemple crée un list explicitement dans la portée de self.

Plus intéressant serait l'exemple:

class testClass():
    list = ['foo']
    def __init__(self):
        self.list = []
        self.list.append('thing')

x = testClass()
print x.list
print testClass.list
del x.list
print x.list

Cela imprimera:

['thing']
['foo']
['foo']

Au moment où vous supprimez le nom de l'instance, le nom de la classe est visible via la référence self.

47
rodrigo

Python a des règles intéressantes sur la recherche de noms. Si vous voulez vraiment vous décourager, essayez ce code:

class testClass():
    l = []
    def __init__(self):
        self.l = ['fred']

Cela donnera à chaque instance une variable appelée l qui masque la variable de classe l. Vous pourrez toujours accéder à la variable de classe si vous le faites self.__class__.l.

La façon dont j'y pense est la suivante ... Chaque fois que vous le faites instance.variable (même pour les noms de méthode, ce ne sont que des variables dont les valeurs se trouvent être des fonctions) il le recherche dans le dictionnaire de l'instance. Et s'il ne le trouve pas, il essaie de le rechercher dans le dictionnaire de classe de l'instance. C'est seulement si la variable est en cours de "lecture". S'il est affecté à, il crée toujours une nouvelle entrée dans le dictionnaire d'instances.

5
Omnifarious

Dans votre premier exemple, list est un attribut de la classe, partagé par toutes ses instances. Cela signifie que vous pouvez même y accéder sans avoir un objet de type testClass:

>>> class testClass():
...     list = []
...     def __init__(self):
...             self.list.append("thing")
... 
>>> testClass.list
[]
>>> testClass.list.append(1)
>>> testClass.list
[1]

Mais tous les objets partagent l'attribut list avec la classe et entre eux:

>>> testObject = testClass()
>>> testObject.list
[1, 'thing']
>>> testClass.list
[1, 'thing']
>>> 
>>> testObject2 = testClass()
>>> testClass.list
[1, 'thing', 'thing']
>>> testObject2.list
[1, 'thing', 'thing']
3
Wieland

Lorsque vous instanciez une classe, __init__ la méthode est exécutée automatiquement.

Dans le premier cas, votre liste est un attribut de classe et est partagée par toutes ses instances. Vous avez deux choses parce que vous en avez ajouté une lors de l'instanciation de p et une autre lors de l'instanciation de f (la première a déjà été ajoutée lors du premier appel).

0
joaquin