Phương thức kế thừa và init trong Python


94

Tôi ăn mày với trăn. Tôi không thể hiểu thừa kế và __init__().

class Num:
    def __init__(self,num):
        self.n1 = num

class Num2(Num):
    def show(self):
        print self.n1

mynumber = Num2(8)
mynumber.show()

KẾT QUẢ: 8

Điều này là OK. Nhưng tôi thay thế Num2bằng

class Num2(Num):
    def __init__(self,num):
        self.n2 = num*2
    def show(self):
        print self.n1,self.n2

KẾT QUẢ: Error. Num2 has no attribute "n1".

Trong trường hợp này, làm thế nào có thể Num2truy cập n1?

Câu trả lời:


148

Trong tình huống đầu tiên, Num2là mở rộng lớp Numvà vì bạn không xác định lại phương thức đặc biệt có tên __init__()trong Num2đó, nó sẽ được kế thừa từ đó Num.

Khi một lớp định nghĩa một __init__() phương thức, việc khởi tạo lớp sẽ tự động gọi __init__()cho cá thể lớp mới được tạo.

Trong tình hình thứ hai, kể từ khi bạn đang đánh giá lại __init__()trong Num2bạn cần phải gọi một cách rõ ràng một trong lớp siêu ( Num) nếu bạn muốn mở rộng hành vi của nó.

class Num2(Num):
    def __init__(self,num):
        Num.__init__(self,num)
        self.n2 = num*2

23
Trích dẫn của bạn không đủ để giải thích tại sao khi không xác định một __init__phương thức trong lớp dẫn xuất, nó được kế thừa. Đó là bởi vì "nếu một thuộc tính được yêu cầu không được tìm thấy trong lớp, thì việc tìm kiếm sẽ tiến hành tìm kiếm trong lớp cơ sở." (doc)
eyquem

5
Tôi xin lỗi ... về cơ bản đó là cách kế thừa hoạt động ... nếu bạn kế thừa một lớp, bạn sẽ nhận được toàn bộ gói, vì vậy, mọi thứ trong lớp cha đều tồn tại trong lớp con. Nhưng, nếu bạn xác định lại một phương thức, nó sẽ bị ghi đè ... đó là những gì có trong mã của bạn.
coya

4
@ mario-duarte bất kỳ lý do nào tại sao điều này sẽ tốt hơn super(Num2, self).__init__(num)?
guival

1
Tôi vừa chuyển từ giải pháp được đề xuất trong câu trả lời này sang sử dụng supervà chương trình của tôi hiện tải nhanh hơn vài giây. Không biết tại sao.
Guimoute

superđược cho là hữu ích khi sử dụng đa kế thừa. Đối với thừa kế đơn lẻ, lợi ích của nó không rõ ràng.
Johann Bzh


4

Vì bạn không gọi Num.__init__, trường "n1" không bao giờ được tạo. Gọi nó và sau đó nó sẽ ở đó.


3

Một thay đổi đơn giản trong lớp Num2 như thế này:

super().__init__(num) 

Nó hoạt động trong python3.

class Num:
        def __init__(self,num):
                self.n1 = num

class Num2(Num):
        def __init__(self,num):
                super().__init__(num)
                self.n2 = num*2
        def show(self):
                print (self.n1,self.n2)

mynumber = Num2(8)
mynumber.show()

1
Đây là lý do tại sao tôi thích stackoverflow. Mặc dù đây không phải là câu trả lời cho câu hỏi nhưng nó hữu ích. Đôi khi câu trả lời mà mọi người đăng là câu trả lời cho câu hỏi mà mọi người nên hỏi. Cảm ơn bạn!
Glen Thompson
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.