2015-09-11 19 views
5

Tôi đã xem câu hỏi về Stack Overflow Counting instances of a class? và tôi không chắc tại sao giải pháp đó hoạt động và một giải pháp sử dụng tính năng bổ sung đơn giản thì không. Tôi đoán đây là một câu hỏi về cách biến lớp và các biến mẫu được lưu trữ và truy cập.Thay đổi thuộc tính lớp trong __init__

Dưới đây là đoạn code tôi nghĩ nên làm việc, nhưng thay vì tạo ra 4 cho mỗi id:

class foo(): 
     num = 3 # trying 3 instead of 0 or 1 to make sure the add is working 

     def __init__(self): 
     self.num += 1 
     self.id = self.num 

f = foo() 
g = foo() 

print f.id # 4 
print g.id # 4 

Tuyên bố self.num +=1 có phần làm việc (việc bổ sung đang xảy ra, nhưng không phải là nhiệm vụ).

Điều gì đang xảy ra dưới mui xe khiến nhiệm vụ này không thành công ở đây, trong khi nhiệm vụ itertools.count thành công trong giải pháp của câu hỏi khác?

Trả lời

4

self.num += 1 có nghĩa là, về cơ bản, 'lấy giá trị là self.num, tăng nó và gán cho self.num.

Tra cứu thuộc tính trên self sẽ tìm biến lớp nếu không có biến mẫu tương ứng. Tuy nhiên, chỉ định sẽ luôn ghi vào một biến mẫu. Vì vậy, điều này cố gắng tìm một thể hiện var, thất bại, rơi trở lại một lớp var, nhận giá trị, tăng nó, sau đó gán cho một cá thể var.

Lý do câu trả lời cho câu hỏi được liên kết hoạt động là vì không có bài tập nào đang diễn ra; họ gọi số next() trực tiếp trên biến lớp, giá trị của nó bị đột biến nhưng tên không được gán lại.

5

Số nguyên không triển khai __iadd__ (bổ sung tại chỗ, cho +=), vì chúng không thay đổi. Các thông dịch viên rơi trở lại để phân công chuẩn và __add__ thay vào đó, do đó, dòng:

self.num += 1 

trở thành:

self.num = self.num + 1 

Về phía bên tay phải bạn sẽ có được foo.num (tức 3) thông qua self.num, như bạn mong đợi , nhưng điều thú vị ở đây là chỉ định gán cho thuộc tính dụ numbóng thuộc tính lớp. Vì vậy, các dòng thực sự là tương đương với:

self.num = foo.num + 1 # instance attribute equals class attribute plus one 

Tất cả trường kết thúc với self.num == 4lớp vẫn foo.num == 3. Thay vào đó, tôi nghi ngờ những gì bạn muốn là:

foo.num += 1 # explicitly update the class attribute 

Ngoài ra, bạn có thể thực hiện nó như là một @classmethod, làm việc trên lớp một cách rõ ràng hơn:

class Foo(): # note naming convention 

    num = 3 

    def __init__(self): 
     self.increment() 
     self.id = self.num # now you're still accessing the class attribute 

    @classmethod 
    def increment(cls): 
     cls.num += 1 
+0

Ngoài ra, 'tự .__ lớp __ num + = 1' – robert

+1

@robert rằng sẽ làm việc, nhưng tôi thấy nó hơi lúng túng – jonrsharpe

2

phân Augmented không cập nhật lớp biến.Nó thực hiện điều này:

tmp = self.num 
self.num = tmp.__iadd__(1) 

Lưu ý chuyển nhượng trở lại self.num ở đó! Như vậy thuộc tính lớp của bạn vẫn bị ảnh hưởng. object.__iadd__() method cho số nguyên không thể thay đổi số tại chỗ bởi vì số nguyên là không thay đổi, vì vậy foo.num không bao giờ thay đổi.

Bạn cần phải tham khảo một cách rõ ràng biến lớp:.

foo.num += 1 

hoặc

self.__class__.num += 1 
Các vấn đề liên quan