Переменные экземпляра класса 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']
большое спасибо
джон
Ответы
Ответ 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
(первый был уже добавлен при первом вызове).