2012-03-17 28 views
12

Tôi đã xác định một lớp Listener và đã tạo một từ điển gồm Listener đối tượng. Mỗi người nghe có một số id để xác định họ và danh sách artists họ nghe, artists = []. Thêm một cái gì đó vào danh sách artists thêm nó cho tất cả các trường hợp của lớp Listener, thay vì trường hợp được giới thiệu. Đây là vấn đề của tôi.Danh sách là thành viên của lớp python, tại sao nội dung của nó được chia sẻ trên tất cả các phiên bản của lớp?

Lớp Listener được định nghĩa như sau:

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 

Đây là mã của tôi gỡ lỗi thử nghiệm:

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) 

Và kết quả:

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'] 

kết quả mong muốn của tôi là cuộc gọi cuối cùng addArtist("Ace of Base", 5) sẽ dẫn đến kết quả là

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

Đây có phải là sự tinh tế của Python mà tôi không hiểu không? Tại sao đây là đầu ra và làm thế nào tôi có thể nhận được đầu ra mong muốn thay vào đó? Cảm ơn!

Trả lời

24

Bạn không muốn các thành viên khai báo trong lớp, nhưng chỉ cần đặt trong __init__ phương pháp:

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 

Nếu bạn có một lớp như

class A: 
    x=5 

Sau đó x là thành viên của lớp và không phải là thành viên của các cá thể của lớp đó. Điều này có thể gây nhầm lẫn, vì trăn phép bạn truy cập các thành viên lớp thông qua các ví dụ:

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

Nhưng bạn cũng có thể truy cập nó thông qua các lớp học riêng của mình:

>>> print A.x 
5 

Nó thậm chí có thể thấy rằng điều này làm việc đúng cách:

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

nhưng điều thực sự xảy ra là bạn đã đặt x mới vào thể hiện a1, sẽ được in thay vì thành viên lớp, vẫn có giá trị ban đầu:

>>> print A.x 
5 

Bạn chỉ bắt đầu thấy một sự khác biệt khi bạn có một cái gì đó có thể thay đổi, giống như một danh sách:

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

Đây có phải là một sự tinh tế của Python Tôi không hiểu?

Nó không tinh tế, nó khá đơn giản; không giống như các ngôn ngữ khác gây nhầm lẫn vấn đề, trong Python tất cả mọi thứ bạn khai báo bên trong lớp thuộc về lớp. Điều này là tự nhiên, vì các lớp là các đối tượng (như mọi thứ khác), và do đó là một nơi hoàn toàn hợp lệ để đính kèm mọi thứ. Do đó, tất cả các phương thức đó thuộc về lớp (thay vì được sao chép một cách kỳ diệu vào từng cá thể), và các thuộc tính dữ liệu cũng vậy.

Mỗi người nghe có một id để xác định chúng

Vâng, bởi vì bạn đính kèm một đến mỗi trường hợp trong __init__. Điều này có không có gì để làm với số id thuộc về lớp học - ngoại trừ khi bạn tra cứu id qua một trường hợp, ví dụ id của trường hợp đó sẽ được tìm thấy, ẩn lớp thuộc lớp đó.

và một danh sách các nghệ sĩ mà họ lắng nghe, nghệ sĩ = []

Khi bạn nhìn lên artists thông qua các lớp, tuy nhiên, lớp artists sẽ được tìm thấy, vì dụ không có một.

Thêm mục nào đó vào danh sách các nghệ sĩ cho biết thêm nó cho tất cả các trường của lớp Listener

Không; nó được thêm vào chính lớp đó, đây là nơi mọi thứ được tìm kiếm khi chúng không được tìm thấy trong ví dụ.

Hãy nhớ rằng nếu bạn đã chuyển nhượng trực tiếp như self.artists = [] trên một trường hợp sau đó, trường hợp đó sẽ có danh sách riêng ẩn danh sách của lớp đó. Các trường hợp khác sẽ không, vì mã đó không chạy trên các phiên bản khác.

Các vấn đề liên quan