Да, это потому, что один неизменен, а другой нет. Вернее, это то, что вы мутируете одно, а не другое. (Важно то, что объект «изменен», имеет значение, действительно ли вы его мутируете.) Это также потому, что вы используете переменные класса вместо переменных экземпляра (см. this question).
В своем определении класса вы создаете три переменные класса, разделяемые между всеми экземплярами класса. После создания экземпляра вашего класса, если вы делаете self.x
в этом экземпляре, он не найдет x
в качестве атрибута экземпляра, но будет искать его в классе. Аналогично self.z
будет искать класс и найти тот, что есть на классе. Обратите внимание, что поскольку вы указали z
переменную класса, существует только один список, который является общим для всех экземпляров класса (включая все экземпляры всех подклассов, если они не переопределяют z
).
Когда вы self.y = self.x
, вы создаете новый атрибут, в экземпляра атрибут только на экземпляре.
Однако, когда вы делаете self.z.append(...)
, вы не создаете новую переменную экземпляра. Скорее, self.z
просматривает список, хранящийся в классе, а затем append
мутирует этот список. Нет «переписывания». Существует только один список, и когда вы добавляете приложение, вы меняете его содержимое. (Добавляется только один элемент, потому что у вас есть if not self.z
, поэтому после того, как вы добавите один из них, это ложные и последующие вызовы не добавят ничего больше.)
Результатом является то, что чтение значения атрибута не является таким же, как назначая ему. Когда вы читаете значение self.x
, вы можете получить значение, которое хранится в классе и разделяемое между всеми экземплярами. Однако, если вы назначили значение self.x
, вы всегда назначаете атрибут экземпляра; если уже есть атрибут класса с тем же именем, ваш атрибут экземпляра скроет это.
спасибо, что имеет смысл –