2012-01-02 54 views
26

có vấn đề khi hiểu các biến lớp/thể hiện hoạt động như thế nào trong python. Tôi không hiểu tại sao khi tôi thử mã này biến danh sách có vẻ là một biến lớpbiến thể hiện lớp python và biến lớp

class testClass(): 
    list = [] 
    def __init__(self): 
     self.list.append('thing') 

p = testClass() 
print p.list 

f = testClass() 
print f.list 

đầu ra:

['thing'] 
['thing', 'thing'] 

và khi tôi làm điều này nó có vẻ là một thể hiện biến

class testClass(): 
    def __init__(self): 
     self.list = [] 
     self.list.append('thing') 

p = testClass() 
print p.list 

f = testClass() 
print f.list 

đầu ra:

['thing'] 
['thing'] 

cảm ơn nhiều

jon

+1

Nếu tôi hiểu chính xác, bạn đang yêu cầu lý do đằng sau quyết định thiết kế cụ thể liên quan đến cú pháp của Python. Đối với những câu hỏi như vậy, câu trả lời hay nhất là "bởi vì nó phù hợp với tinh thần của ngôn ngữ", hoặc nhiều hơn nữa: "hỏi người sáng tạo của nó". – Xion

+0

ok vì vậy biến là biến lớp theo mặc định, đó là nơi mà sự nhầm lẫn của tôi bắt nguồn từ, đó phải là câu hỏi của tôi, làm biến mặc định cho biến lớp –

+4

@jonathantopf Không, biến không phải là biến lớp theo mặc định. Trong Python bạn không khai báo varables. Cho rằng vấn đề, họ không thực sự biến (python là một _variableless_ lanuage), chỉ cần tên. Và bạn không khai báo hoặc assing tên, bạn _bind_ chúng vào một đối tượng. Và mỗi đối tượng trong thời gian chạy có một từ điển tên đối tượng. Và ngay cả khi hai vật thể thuộc cùng một lớp, chúng có thể có các từ điển rất khác nhau. – rodrigo

Trả lời

40

Đây là vì cách giải quyết Python tên với .. Khi bạn viết self.list thời gian chạy Python cố gắng giải quyết tên list đầu tiên tìm kiếm nó trong đối tượng thể hiện và nếu không tìm thấy trong cá thể lớp.

Chúng ta hãy nhìn vào nó từng bước

self.list.append(1) 
  1. Có một tên list vào đối tượng self?
    • Có: Sử dụng nó! Hoàn thành.
    • Số: Tới 2.
  2. Có một tên list vào dụ lớp của đối tượng self?
    • Có: Sử dụng nó! Hoàn thành
    • Không: Lỗi!

Nhưng khi bạn gắn một tên điều là khác nhau:

self.list = [] 
  1. Có một tên list vào đối tượng self?
    • Có: Ghi đè lên!
    • Không: Liên kết nó!

Vì vậy, đó luôn là biến mẫu.

Ví dụ đầu tiên của bạn tạo ra một list vào trường hợp lớp, vì đây là phạm vi hoạt động tại thời điểm đó (không có self ở bất kỳ đâu). Nhưng ví dụ thứ hai của bạn tạo ra một số list một cách rõ ràng trong phạm vi self.

More thú vị sẽ là ví dụ:

class testClass(): 
    list = ['foo'] 
    def __init__(self): 
     self.list = [] 
     self.list.append('thing') 

x = testClass() 
print x.list 
print testClass.list 
del x.list 
print x.list 

Đó sẽ in:

['thing'] 
['foo'] 
['foo'] 

Thời điểm bạn xóa các dụ đặt tên cho tên lớp là có thể nhìn thấy qua self tham khảo.

+0

ok im sau, trong trường hợp đó là có một cách để xác định các biến mẫu bên ngoài hàm __init__, tôi chỉ cố gắng làm 'self.list []' bên ngoài __init__, điều này có ý nghĩa nhưng có cách nào không? –

+0

@jonathantopf: Các biến cá thể chỉ có thể được tạo khi bạn có một cá thể. Chúng phải được tạo ra trong một phương thức được gọi là một bản sao. Lựa chọn khác của bạn là quá tải '__new__' và tạo chúng ở đó, nhưng điều đó thực sự xấu vì nó không phải là những gì' __new__' thực sự là, và nó không thực sự tốt hơn là tạo chúng trong '__init__'. Điều gì, hãy cầu nguyện, bạn có nghĩ mình cần khả năng này không? Bạn có thể tạo một siêu lớp mà quá tải '__new__' để xem qua dict của lớp và sao chép mọi thứ vào dict dụ. Nhưng đó là ** thực sự ** xấu xí. – Omnifarious

+0

:) điểm lấy, có ý nghĩa, tôi ghét đặt câu hỏi như thế nhưng đôi khi nó là cách tốt nhất để tìm hiểu xem những gì im suy nghĩ là điên hay không, bây giờ tôi biết! –

0

Khi bạn khởi tạo một lớp, phương thức __init__ được tự động thực thi.

Trong trường hợp đầu tiên, danh sách của bạn là thuộc tính lớp và được chia sẻ bởi tất cả các trường hợp của nó. Bạn có hai 'điều bởi vì bạn nối thêm một khi instantitating p và khác khi instantiated f (một trong những đầu tiên đã được nối thêm tại cuộc gọi đầu tiên).

3

Trong ví dụ đầu tiên của bạn, list là thuộc tính của lớp, được chia sẻ bởi tất cả các phiên bản của nó. Điều này có nghĩa rằng bạn thậm chí có thể truy cập vào nó mà không cần phải một đối tượng kiểu testClass:

>>> class testClass(): 
...  list = [] 
...  def __init__(self): 
...    self.list.append("thing") 
... 
>>> testClass.list 
[] 
>>> testClass.list.append(1) 
>>> testClass.list 
[1] 

Nhưng tất cả đối tượng chia sẻ các thuộc tính list với lớp và mỗi khác:

>>> testObject = testClass() 
>>> testObject.list 
[1, 'thing'] 
>>> testClass.list 
[1, 'thing'] 
>>> 
>>> testObject2 = testClass() 
>>> testClass.list 
[1, 'thing', 'thing'] 
>>> testObject2.list 
[1, 'thing', 'thing'] 
4

Python có quy tắc thú vị về tìm kiếm lên tên. Nếu bạn thực sự muốn uốn cong tâm trí của bạn, hãy thử mã này:

class testClass(): 
    l = [] 
    def __init__(self): 
     self.l = ['fred'] 

này sẽ cung cấp cho mỗi trường hợp một biến gọi là l rằng mặt nạ lớp biến l. Bạn sẽ vẫn có thể nhận được biến lớp nếu bạn làm self.__class__.l.

Cách tôi nghĩ về điều này là ... Bất cứ khi nào bạn làm instance.variable (ngay cả đối với tên phương thức, chúng chỉ là các biến có giá trị là hàm), nó tìm kiếm trong từ điển của cá thể. Và nếu nó không thể tìm thấy nó ở đó, nó sẽ tìm kiếm nó trong từ điển của lớp học. Điều này chỉ xảy ra nếu biến đang được 'đọc'. Nếu nó được gán cho nó, nó luôn tạo một mục mới trong từ điển cá thể.

+0

Biến chứng đáng sợ nào! Câu trả lời này thực sự hữu ích, bởi vì trường hợp 'đọc và viết' đã khiến tôi đau đầu. – dotslash

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