переменные класса разделяются между всеми экземплярами в Python?

Я начал кодировать на python неделю назад, это моя ошибка, я начал кодировать, используя упс, классы и объекты, которые скоро. Я полагал, что мои знания C ++ помогут .... Меня укусил следующий код

class A:
     var=0
     list=[]
     def __init__(self):
            pass

Здесь, к моему удивлению, var и list - это своего рода глобальные переменные, они, похоже, используются во всех экземплярах .... Я думал, что они были разными для всех экземпляров ... Мне потребовалось полдня, чтобы понять это .... Это не имеет ни малейшего смысла, что переменная может быть доступна только для объекта класса, но является общей для всех экземпляров ....... Просто любопытно, есть ли в этом причина ??? ??


person howtechstuffworks    schedule 14.06.2012    source источник
comment
У меня нет проблем с переменной класса, не принадлежащей классу .... но почему все внешние переменные статичны, без ключевого слова static ....... это противоречит естественному инстинкту ....   -  person howtechstuffworks    schedule 15.06.2012
comment
@howtechstuffworks Все языки имеют разный синтаксис, это просто то, к чему нужно привыкнуть. Из-за динамической природы Python разумно привязать переменную к тому, что она находится внутри (в данном случае к классу, а не к экземпляру класса).   -  person Brendan Long    schedule 15.06.2012


Ответы (4)


var определенно не следует использовать совместно, если вы получаете к нему доступ с помощью instance.var или self.var. Однако со списком ваша инструкция делает следующее: когда класс оценивается, создается один экземпляр списка и привязывается к классу dict, следовательно, все экземпляры будут иметь один и тот же список. Каждый раз, когда вы устанавливаете instance.list = somethingelse соотв. self.list = somethingelse, он должен получить значение уровня экземпляра.

Пример времени:

>>> class A():
...     var = 0
...     list = []
...
>>> a = A()
>>> b = A()
>>> a.var
0
>>> a.list
[]
>>> b.var
0
>>> b.list
[]
>>> a.var = 1
>>> b.var
0
>>> a.list.append('hello')
>>> b.list
['hello']
>>> b.list = ['newlist']
>>> a.list
['hello']
>>> b.list
['newlist']
person mensi    schedule 14.06.2012
comment
То же самое происходит с var, что и с list, разница в том, что вы не можете добавлять к var, как с list, вы можете только объявить другую переменную с тем же именем. - person Brendan Long; 15.06.2012
comment
@BrendanLong неизменяемые типы в этой ситуации отличаются, так как не имеет значения, поделитесь ли вы ими. - person mensi; 15.06.2012
comment
Да, я просто хочу уточнить, что вы разделяете неизменный var, вы просто также заменяете его чем-то другим всякий раз, когда делаете self.var = .... Таким образом, поведение var и list точно такое же, просто list более интересна как общая переменная (поскольку она изменяема). - person Brendan Long; 15.06.2012
comment
Это поведение изменяемых аргументов по умолчанию также обсуждается здесь: docs.python- guide.org/writing/gotchas/ - person Barney Kelly; 10.07.2020

Они в основном похожи на статические переменные в Java:

// Example equivalent Java
class A {
    static int var = 0;
    static String[] list;
}

Это предполагаемое поведение: переменные класса для класса.

Для обычных переменных экземпляра объявите их в конструкторе:

class A:
    def __init__(self):
        self.var = 0
        self.list = []

Вы можете посмотреть Статические переменные класса в Python.

person Brendan Long    schedule 14.06.2012
comment
хорошо, теперь я попробовал пример и почти уверен, что список общий для всех .... Как насчет переменной? он не используется во всех экземплярах (я тестировал его) ..... он все еще статичен, мне нужно больше учиться, прежде чем вернуться к коду .... Спасибо за вашу помощь ....... - person howtechstuffworks; 15.06.2012
comment
@howtechstuffworks Другая переменная тоже статична, но если вы сделаете self.var="something else", тогда вы создадите переменную экземпляра с тем же именем (у вас будут и A.var, и self.var), и предполагается, что вы имеете в виду переменную экземпляра. Вы по-прежнему можете получить доступ к переменной класса с помощью A.var. Вы можете сделать то же самое с list, объявив метод экземпляра с тем же именем (self.list = "something else"). - person Brendan Long; 15.06.2012
comment
Да, на самом деле я переместил все в '__init __ ()', просто еще один вопрос, у меня есть некоторые переменные, которые должны быть общими и не доступными для записи ... подумайте, как макрос в C или const в C ++, где я должен написать это здесь ???? - person howtechstuffworks; 15.06.2012
comment
@howtechstuffworks Обычно вам следует открывать новую ветку для каждого вопроса, но чтобы ответить - Python не имеет констант. Есть несколько приемов для их создания, но общее решение состоит в том, чтобы называть константы в верхнем регистре и предполагать, что пользователи вашего API недостаточно глупы, чтобы их изменять (вы обнаружите, что это обычная тема в Python - вы можете сделать что угодно, но то, что вы можете, не означает, что вы должны). - person Brendan Long; 15.06.2012

Причина в том, что в Python class - это исполняемый оператор, который выполняется так же, как и любой другой. Тело определения класса выполняется один раз, когда класс определен. Если у вас есть строчная строка var = [], то она выполняется только один раз, поэтому в результате этой строки может быть создан только один список.

person BrenBarn    schedule 14.06.2012

Обратите внимание, что вы не видите этого поведения для var, вы видите его только для list:

>>> class A:
...     var = 0
...     list = []
... 
>>> a1 = A()
>>> a2 = A()
>>> a1.var = 3
>>> a2.var
0
person Simeon Visser    schedule 14.06.2012
comment
^ да, согласен .... но все равно непонятно .... - person howtechstuffworks; 15.06.2012
comment
Это потому, что Python ищет переменную экземпляра перед переменной класса. В вашем случае var вы добавляете переменную экземпляра, которая затем имеет приоритет. - person Brendan Long; 15.06.2012
comment
@BrendanLong, почему var переменная экземпляра, а list нет, если они определены одинаково? - person Forever; 08.08.2017