2012-03-17 9 views
12

Zdefiniowałem klasę Listener i utworzyłem słownik obiektów Listener. Każdy słuchający ma id, aby je zidentyfikować, oraz listę artists, której słuchają, artists = []. Dodanie czegoś do listy artists dodaje ją do wszystkich wystąpień klasy Listener, a nie do polecanej instancji. To jest mój problem.Wyświetl jako członka klasy Pythona, dlaczego jego zawartość jest udostępniana we wszystkich instancjach klasy?

Klasa Listener jest zdefiniowany następująco:

class Listener: 
    id = "" 
    artists = [] 

    def __init__(self, id): 
     self.id = id 

    def addArtist(self, artist, plays): 
     print self.id # debugging... 
     print "pre: ", self.artists 
     self.artists.append(artist) 
     print "post: ", self.artists 

Oto moja debugowanie kodu testu:

def debug(): 
    listeners = {} 
    listeners["0"] = Listener("0") 
    listeners["1"] = Listener("1") 

    listeners["0"].addArtist("The Beatles", 10) 
    listeners["0"].addArtist("Lady Gaga", 4) 
    listeners["1"].addArtist("Ace of Base", 5) 

a wyjście:

0 
pre: [] 
post: ['The Beatles'] 
0 
pre: ['The Beatles'] 
post: ['The Beatles', 'Lady Gaga'] 
1 
pre: ['The Beatles', 'Lady Gaga'] 
post: ['The Beatles', 'Lady Gaga', 'Ace of Base'] 

Moje oczekiwany wynik jest taki, że Ostateczne połączenie addArtist("Ace of Base", 5) spowoduje wygenerowanie wyniku

1 
pre: [] 
post: ['Ace of Base'] 

Czy to subtelność Pythona, którego nie rozumiem? Dlaczego to jest wyjście i jak mogę zamiast tego uzyskać pożądany wynik? Dzięki!

Odpowiedz

24

Nie chcesz członkowie zadeklarowane wewnątrz klasy, ale po prostu ustawić w metodzie __init__:

class Listener: 
    def __init__(self, id): 
     self.id = id 
     self.artists = [] 

    def addArtist(self, artist, plays): 
     print self.id # debugging... 
     print "pre: ", self.artists 
     self.artists.append(artist) 
     print "post: ", self.artists 

Jeśli masz klasę jak

class A: 
    x=5 

to X jest członkiem klasa, a nie członek instancji tej klasy. Może to być mylące, ponieważ Python umożliwia dostęp członków klasy poprzez przykład:

>>> a=A() 
>>> print a.x 
5 

Ale można też uzyskać do niego dostęp za pośrednictwem klasy samego:

>>> print A.x 
5 

Byłoby nawet wydawać, że to działa prawidłowo:

>>> a1=A() 
>>> a2=A() 
>>> a1.x=6 
>>> print a1.x 
6 
>>> print a2.x 
5 

ale to, co rzeczywiście się stało jest to, że umieściliśmy nowy X na instancji a1, które zostaną wydrukowane zamiast członka klasy, która nadal ma swoją pierwotną wartość:

>>> print A.x 
5 

Wystarczy tylko zacząć, aby zobaczyć różnicę, gdy masz coś, co można zmienić, jak listy:

class A: 
    l=[] 

>>> a1=A() 
>>> print a1.l 
[] 
>>> a2=A() 
>>> print a2.l 
[] 
>>> a1.l.append(5) 
>>> print a1.l 
[5] 
>>> print a2.l 
[5] 
>>> print A.l 
[5] 
4

Czy to subtelność Pythonie nie mam zrozumienia?

Nie jest subtelny, jest dość prosty; w przeciwieństwie do innych języków, które wprowadzają zamieszanie w błąd, w Pythonie wszystko, co deklarujesz wewnątrz klasy, należy do klasy. Jest to naturalne, ponieważ klasy są przedmiotami (jak wszystko inne), a więc idealnym miejscem do dołączania rzeczy. Zatem wszystkie te metody należą do klasy (zamiast być w jakiś sposób magicznie kopiowane do każdej instancji), podobnie jak atrybuty danych.

Każdy słuchacz ma id do ich identyfikacji

Tak, ponieważ dołączyć jeden do każdej instancji w __init__. To ma wartość nic wspólnego z z id, która należy do klasy - z tą różnicą, że podczas wyszukiwania id przez instancję, zostanie znaleziona własna instancja id, ukrywając tę ​​należącą do klasy.

oraz lista artystów Słuchają, artystów = []

Kiedy patrzysz w górę artists za pośrednictwem klasy, jednak klasa artists zostanie znaleziony, ponieważ instancja nie mieć jeden.

dodanie czegoś do listy artystów dodaje go do wszystkich instancji klasy Listener

Nie; dodano do samej klasy, czyli tam, gdzie rzeczy są poszukiwane, gdy nie są znalezione w instancji.

Należy pamiętać, że jeśli później wykonasz zadanie, takie jak self.artists = [], instancja otrzyma własną listę, ukrywając listę klas. Inne instancje nie, ponieważ ten kod nie został uruchomiony w innych instancjach.

Powiązane problemy