2010-04-25 2 views
1
>>> class Abcd: 

...  a = '' 
...  menu = ['a', 'b', 'c'] 
... 
>>> a = Abcd() 
>>> b = Abcd() 
>>> a.a = 'a' 
>>> b.a = 'b' 
>>> a.a 
'a' 
>>> b.a 
'b' 

Это все правильно, и каждый объект имеет свой собственный «а», но ...Python. Странное поведение атрибутов класса

>>> a.menu.pop() 
'c' 
>>> a.menu 
['a', 'b'] 
>>> b.menu 
['a', 'b'] 

Как это могло произойти? И как использовать список как атрибут класса?

+0

Вы определенно не первый, чтобы работать в этом. Я помню, как впервые попал в эту проблему: мне потребовались дни, чтобы понять, в чем проблема. Это имеет смысл, как только вы это узнаете, но я лично считаю, что это действительно неинтуитивно. –

+0

@musicfreak: Я действительно не понимаю, почему люди смущены этим. Изучая любой пример OO в любом учебнике, вы узнаете об этом. Почему каждый предпочитает тратить «дни» вместо того, чтобы инвестировать несколько часов, чтобы прочитать учебник, вне меня. – nikow

+0

-1: Для этого есть много дубликатов. – nikow

ответ

7

Это связано с тем, что так, как вы инициализируете свойство menu, все экземпляры указывают на тот же список, в отличие от разных списков с одинаковым значением.

Вместо этого используйте функцию __init__ члена класса для инициализации значений, создавая тем самым новый список и назначая этот список имущества для конкретного экземпляра класса:

class Abcd: 
    def __init__(self): 
     self.a = '' 
     self.menu = ['a', 'b', 'c'] 
+0

Но что же касается различного простого атрибута строки и атрибута списка? Почему? – Eugene

+1

Потому что это разница между ссылкой и значением. Если вы делали 'a.menu = ['a', 'b']', тогда 'b.menu' остался бы без изменений, но вы не, вы меняете список *, указываемый * на' a. menu'. – Amber

4

См class-objects в руководстве , и обратите внимание на использование self.

Использование экземпляра атрибутов, а не атрибуты класса (а также новые классы стиля):

>>> class Abcd(object): 
...  def __init__(self): 
...   self.a = '' 
...   self.menu = ['a','b','c'] 
...   
>>> a=Abcd() 
>>> b=Abcd() 
>>> a.a='a' 
>>> b.a='b' 
>>> a.a 
'a' 
>>> b.a 
'b' 
>>> a.menu.pop() 
'c' 
>>> a.menu 
['a', 'b'] 
>>> b.menu 
['a', 'b', 'c'] 
>>> 
+0

Возможно, вы захотите отметить, что все классы автоматически являются классами нового стиля в строке Python 3.0+. –

0

, поскольку переменные в Python просто "метки"

как Abcd.menu и a.menu ссылаться на тот же объект списка.

в вашем случае следует присвоить метку на новый объект,

не изменяет объект InPlace.

Вы можете запустить

a.menu = a.menu[:-1] 

вместо

a.menu.pop() 

почувствовать разницу