Подтвердить что ты не робот

Переменные экземпляра класса python и переменные класса

im имеет проблему, понимающую, как переменные класса/экземпляра работают в python. Я не понимаю, почему, когда я пытаюсь использовать этот код, переменная списка кажется переменной класса

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

p = testClass()
print p.list

f = testClass()
print f.list

выход:

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

и когда я делаю это, это, как представляется, переменная экземпляра

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

p = testClass()
print p.list

f = testClass()
print f.list

выход:

['thing']
['thing']

большое спасибо

джон

4b9b3361

Ответ 1

Это связано с тем, как Python разрешает имена с помощью .. Когда вы пишете self.list, среда выполнения Python пытается разрешить имя list, которое сначала ищет его в объекте экземпляра, а если не найдено в экземпляре класса.

Посмотрите на это шаг за шагом.

self.list.append(1)
  • Есть ли в объекте self имя list?
    • Да: используйте его! Готово.
    • Нет: перейдите к 2.
  • Есть ли в экземпляре класса объект self имя list?
    • Да: используйте его! Готово
    • Нет: ошибка!

Но когда вы связываете имя, все по-другому:

self.list = []
  • Есть ли в объекте self имя list?
    • Да: перезапишите его!
    • Нет: привяжите его!

Итак, это всегда переменная экземпляра.

В первом примере создается экземпляр list в экземпляр класса, так как это активная область в то время (no self где-либо). Но ваш второй пример создает list явно в области self.

Более интересным был бы пример:

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

Это напечатает:

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

В момент удаления имени экземпляра имя класса отображается через ссылку self.

Ответ 2

У Python есть интересные правила поиска имен. Если вы действительно хотите согнуть свой разум, попробуйте этот код:

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

Это даст каждому экземпляру переменную с именем l, которая маскирует переменную класса l. Вы все равно сможете получить переменную класса, если вы выполняете self.__class__.l.

То, как я думаю об этом, это... Всякий раз, когда вы делаете instance.variable (даже для имен методов, это просто переменные, значения которых являются функциями), это выглядит в словаре экземпляра. И если он не может найти его там, он пытается найти его в словаре класса экземпляра. Это происходит только в том случае, если переменная "читается". Если ему назначено, он всегда создает новую запись в словаре экземпляра.

Ответ 3

В вашем первом примере list является атрибутом класса, общим для всех его экземпляров. Это означает, что вы даже можете получить к нему доступ без объекта типа testClass:

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

Но все объекты совместно используют атрибут list с классом и друг с другом:

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

Ответ 4

Когда вы создаете экземпляр класса, метод __init__ выполняется автоматически.

В первом случае ваш список является атрибутом класса и используется всеми его экземплярами. У вас есть две вещи, потому что вы добавили их при создании экземпляра p, а другой при создании экземпляра f (первый был уже добавлен при первом вызове).