2012-01-13 38 views
23

Tôi là người Java mới bắt đầu học Python. Lấy ví dụ này:Thừa kế các thuộc tính trong python bằng __init__

class Person(): 
    def __init__(self, name, phone): 
     self.name = name 
     self.phone = phone 

class Teenager(Person): 
    def __init__(self, name, phone, website): 
     self.name=name 
     self.phone=phone 
     self.website=website 

Tôi chắc chắn có nhiều mã dự phòng (tôi biết trong Java, có rất nhiều dự phòng cho mã bit ở trên).

Những phần nào là thừa đối với những thuộc tính nào đã được kế thừa từ lớp cha?

Trả lời

29

Khi viết hàm __init__ cho một lớp trong python, bạn nên luôn gọi hàm __init__ của lớp cha của nó. Chúng ta có thể sử dụng để vượt qua các thuộc tính có liên quan trực tiếp đến lớp cha, do đó, mã của bạn sẽ trông như thế này:

class Person(object): 
    def __init__(self, name, phone): 
     self.name = name 
     self.phone = phone 
class Teenager(Person): 
    def __init__(self, name, phone, website): 
     Person.__init__(self, name, phone) 
     self.website=website 

Như những người khác đã chỉ ra, bạn có thể thay thế dòng

Person.__init__(self, name, phone) 

với

super(Teenager, self).__init__(name, phone) 

và mã sẽ thực hiện tương tự. Điều này là bởi vì trong python instance.method(args) chỉ là viết tắt của Class.method(instance, args). Nếu bạn muốn sử dụng super, bạn cần đảm bảo rằng bạn chỉ định object làm lớp cơ sở cho Person như tôi đã thực hiện trong mã của mình.

python documentation có thêm thông tin về cách sử dụng từ khóa super. Điều quan trọng trong trường hợp này là nó nói với python để tìm phương thức __init__ trong một lớp cha của self không phải là Teenager

+2

Lưu ý rằng nếu bạn đang sử dụng Python 2.x, bạn phải liệt kê rõ ràng 'đối tượng' làm lớp cơ sở của' Person' để sử dụng 'super()'. Nếu không, bạn phải sử dụng biểu mẫu 'Person .__ init__'. – chepner

+0

@chepner bạn có thể cung cấp tham chiếu cho điều đó không? Tôi không thể tìm thấy. – murgatroid99

+0

http://docs.python.org/library/functions.html#super chỉ ra rằng super() chỉ được hỗ trợ trên các lớp kiểu mới, trong Python 2.x là các lớp kế thừa từ 'object' – chepner

5

Thuộc tính trong Python không được kế thừa khi chúng được định nghĩa trong hàm tạo và lớp cha nguyên tử không được gọi , trừ khi bạn làm tất cả điều đó bằng tay:

class Person(): 
    def __init__(self, name, phone): 
     self.name = name 
     self.phone = phone 
class Teenager(Person): 
    def_init_(self, name, phone, website): 
     Person.__init__(self, name, phone) # Call parent class constructor. 
     self.website=website 

Thông tin thêm về nó ở đây: http://docs.python.org/tutorial/classes.html#inheritance

1

__init__, không giống như một constructor java, không được tự động kêu gọi mọi tầng lớp trong hệ thống phân cấp thừa kế - bạn cần t o tự mình làm.

Ngoài ra, tất cả các phân cấp đối tượng của bạn phải được bắt nguồn từ số object (ngoại trừ trong trường hợp đặc biệt).

Mã của bạn nên đọc:

class Person(object): 
    def __init__(self, name, phone): 
     self.name = name 
     self.phone = phone 
class Teenager(Person): 
    def_init_(self, name, phone, website): 
     super(Teenager, self).__init__(name, phone) 
     self.website=website 

super tạo ra một đại biểu cho đối số của nó thứ hai (self), mà sẽ gọi hàm tiếp theo trong danh sách các chức năng để kêu gọi mỗi tên (các "phương pháp để giải quyết "). Điều này không hoàn toàn giống như gọi phương thức siêu lớp, như trong Java.

Bạn cũng có thể viết super(type(self), self).__init__(name, phone), nhưng nếu bạn kế thừa thêm từ lớp này, type(self) có thể không là Teenager và bạn có thể có một đệ quy vô hạn. Đây là một hệ quả thực tế của thực tế là bạn đang làm việc với một đối tượng ủy nhiệm với một MRO khác biệt, chứ không phải trực tiếp gọi một hàm tạo siêu lớp.

11

cách Hơi sạch hơn tôi muốn làm điều này:

class Teenager(Person): 
     def __init__(self, *args, **kwargs): 
      self.website=kwargs.pop('website') 
      super(Teenager, self).__init__(*args, **kwargs) 

Nó không có nhiều sự khác biệt trong trường hợp này, nhưng khi bạn có một __init__ với một tấn của các đối số, nó làm cho cuộc sống dễ dàng hơn.

+0

Được bỏ phiếu để sử dụng * args và ** kwargs (... hiệu quả trong trường hợp có nhiều đối số). –

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