2017-08-26 72 views
5

Tôi mong đợi mã sau đây để innhưng nó in 012012. Tại sao? Tôi hy vọng các cuộc gọi sẽ không thể truy cập các biến tương tự vì chúng được thừa hưởng từ cùng một lớp nhưng chúng là các biến khác nhau rõ ràng.phương pháp và lớp thừa kế python

class a(object): 
    var = 0 
    @classmethod 
    def incr(cls): 
     print cls.var 
     cls.var+=1 

class b(a): 
    def func(self): 
     super(b,self).incr() 

class c(a): 
    def func(self): 
     super(c,self).incr() 


t = a() 
t1 = b() 
t2 = c() 
t1.func() 
t1.func() 
t1.func() 
t2.func() 
t2.func() 
t2.func() 
+1

Nó không ảnh hưởng đến hành vi bất ngờ bạn đang nhìn thấy, nhưng tôi muốn lưu ý rằng bạn không cần phải sử dụng 'super' ở đây trong một trong các lớp con của bạn. Bạn có thể chỉ cần gọi 'self.incr()' để thay thế. Bạn chỉ cần sử dụng 'super' khi bạn muốn bỏ qua một phiên bản khác của hàm (thường là vì bạn đã ghi đè trong lớp hiện tại). – Blckknght

+0

Bạn nên chuyển sang Python 3.6. https://pythonclock.org/ – wwii

Trả lời

5

Họ được thừa kế từ lớp như nhau, nhưng cls truyền cho classmethod qua siêu là lớp hiện tại nơi phương pháp này được gọi là từ. super truy cập phiên bản lớp cơ sở của phương pháp, nhưng cls cho cuộc gọi là lớp nơi thực hiện cuộc gọi siêu.

Đây là một trong những tinh tế khác biệt giữa thực hiện:

def func(self): 
    super(c, self).incr() # same as a.__dict__['incr'].__get__(self, type(self))() 

và:

def func(self): 
    a.incr() 

Bạn có thể xác nhận điều này bằng cách in dòng cls trong phương pháp incr của bạn trong cả hai trường hợp:

Bạn không bao giờ nên giả định rằng tất cả super thực hiện lệnh gọi hàm được liên kết với lớp cha. Nó còn nhiều hơn thế nữa.

Hãy nhớ rằng khi bài tập tăng cường đầu tiên += được thực hiện, giá trị ban đầu của var được đọc từ lớp cơ sở (vì tại thời điểm này nó không tồn tại trong dict của lớp con). Tuy nhiên, giá trị cập nhật được ghi vào lớp con. Gọi số super từ lớp con thứ hai lặp lại hành vi tương tự khi đọc giá trị var ban đầu từ a.

+0

Bạn có thể muốn rõ ràng về thực tế rằng đó là dòng 'cls.var + = 1' hoạt động kỳ lạ khi' cls' khác. Lần đầu tiên nó chạy, nó * đọc * giá trị kế thừa của 'var' (là' 0' trong ví dụ này, nhưng có thể có giá trị khác nếu 't.incr()' đã được gọi), nhưng nó * ghi * vào 'cls' cụ thể thay vì cho lớp cơ sở. Tất cả các cuộc gọi tiếp theo sử dụng giá trị của lớp con mà không bao giờ nhìn thấy lớp cơ sở. – Blckknght

+0

@Blckknght Tôi sẽ thêm một lưu ý ngắn về điều đó. –

0

Cả hai lớp b và lớp c được kế thừa từ lớp a riêng biệt và var được đặt thành 0 mỗi lần.

Một cách để có lớp c để có được những giá trị tương tự của var trong lớp a như lớp b không, lớp c có thể kế thừa từ lớp b như vậy:

class a(object): 
    var = 0 
    @classmethod 
    def incr(cls): 
     print cls.var 
     cls.var+=1 

class b(a): 
    def func(self): 
     super(b,self).incr() 

class c(b): 
    def func(self): 
     super(c,self).incr() 


t = a() 
t1 = b() 
t2 = c() 
t1.func() 
t1.func() 
t1.func() 
t2.func() 
t2.func() 
t2.func()` 
+1

Điều đó chỉ cho kết quả mong đợi nếu lệnh gọi đầu tiên tới 't2.func()' xuất hiện sau tất cả các cuộc gọi 't1.func()'. Nếu bạn trộn chúng lên, bạn sẽ không nhận được kết quả mong muốn. Và nó rất sai lầm khi nói rằng "' var' được đặt thành 0 mỗi lần ". Chỉ có một 'var' khi nó bằng 0 (chữ cái trong' a').Đó là sau lệnh gọi 'incr' đầu tiên mà bất kỳ lớp nào nó được tạo ra đều nhận thuộc tính' var' mới với giá trị '1'. – Blckknght

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