2013-07-07 34 views
21

Tôi cố gắng để hiểu khi nào và làm thế nào để sử dụng siêu() trong Python một cách chính xác (hoặc 2.7.x hoặc 3.x)Đối số siêu() của Python: tại sao không siêu (obj)?

trên >>> help(super) người phiên dịch nói với tôi làm thế nào để gọi nó là:

class super(object) 
| super(type) -> unbound super object 
| super(type, obj) -> bound super object; requires isinstance(obj, type) 
| super(type, type2) -> bound super object; requires issubclass(type2, type) 

Tôi hiểu rằng trong Python3.x nó bây giờ có thể sử dụng siêu() trong một định nghĩa lớp, nhưng tôi không hiểu tại sao super(obj) là không thể. Hoặc super(self) trong định nghĩa lớp.

Tôi biết phải có lý do, nhưng tôi không thể tìm thấy. Với tôi những dòng này tương đương với super(obj.__class__, obj) hoặc super(self.__class__, self) và những dòng đó sẽ hoạt động đúng không?

Tôi nghĩ rằng chỉ cần gõ super(obj) sẽ là một lối tắt đẹp ngay cả trong Python 3.x.

+0

Tôi sẽ nói rằng nó sẽ gây ra sự mơ hồ khi bạn gọi 'siêu' trên một metaclass, nhưng sau đó tôi nhận ra rằng sự mơ hồ cũng tồn tại với dạng 2-đối số. Bây giờ tôi không chắc chắn. – user2357112

Trả lời

31

Biểu mẫu hai đối số chỉ cần thiết trong Python 2. Lý do là self.__class__ luôn đề cập đến lớp "lá" trong cây thừa kế - đó là lớp cụ thể nhất của đối tượng - nhưng khi bạn hãy gọi super bạn cần phải cho biết triển khai thực hiện nào hiện đang được gọi, vì vậy nó có thể gọi trình tiếp theo trong cây thừa kế.

Giả sử bạn có:

class A(object): 
    def foo(self): 
     pass 

class B(A): 
    def foo(self): 
     super(self.__class__, self).foo() 

class C(B): 
    def foo(self): 
     super(self.__class__, self).foo() 

c = C() 

Lưu ý rằng c.__class__C, luôn luôn. Bây giờ hãy nghĩ về những gì sẽ xảy ra nếu bạn gọi c.foo().

Khi bạn gọi super(self.__class__, self) theo phương thức C, nó sẽ giống như gọi số super(C, self), có nghĩa là "hãy gọi phiên bản của phương thức này được kế thừa bằng C". Điều đó sẽ gọi B.foo, điều đó là tốt. Nhưng khi bạn gọi super(self.__class__, self) từ B, nó vẫn giống như gọi số super(C, self), bởi vì nó giống nhau self, vì vậy self.__class__ vẫn là C. Kết quả là cuộc gọi trong B một lần nữa sẽ gọi B.foo và một đệ quy vô hạn xảy ra.

Tất nhiên, điều bạn thực sự muốn là có thể gọi super(classThatDefinedTheImplementationThatIsCurrentlyExecuting, self) và đó chính là điều mà Python 3 super() thực hiện.

Trong Python 3, bạn chỉ có thể thực hiện super().foo() và nó thực hiện đúng. Nó không rõ ràng với tôi những gì bạn có ý nghĩa về super(self) là một phím tắt. Trong Python 2, nó không hoạt động vì lý do tôi đã mô tả ở trên. Trong Python 3, nó sẽ là một "longcut" bởi vì bạn chỉ có thể sử dụng đồng bằng super() thay thế.

Sử dụng super(type)super(type1, type2) thỉnh thoảng có thể cần thiết trong Python 3, nhưng chúng luôn sử dụng bí truyền hơn cho các tình huống bất thường.

+0

Một đồng nghiệp đã tái cấu trúc một phần của một phương thức được gọi là 'super' thành một phương thức riêng biệt trong một lớp khác, vì vậy mã kết thúc bằng việc nói 'super (SomeOtherClass, some_obj) .method (...)' trông giống như một lỗi cho bất kỳ ai đọc mã. Mặc dù điều này có thể đã được (và kết thúc được) thể hiện tốt hơn, hình thức hai đối số của 'siêu' vẫn có thể hữu ích trong một số trường hợp cạnh. – user4815162342

+0

4 dòng giải thích đầu tiên của bạn đã giúp tôi hiểu mọi thứ. Cảm ơn bạn cho ví dụ là tốt. Đó là phần còn thiếu mà tôi đang cố hiểu. – Gabriel

+0

Chúng tôi tiếp tục đề cập đến trường hợp 'bí truyền' hoặc 'cạnh'. Đây có phải chỉ đơn giản là khi thừa kế đôi đòi hỏi chúng ta gọi hai hàm '__init __()' riêng biệt khi ghi đè '__init __()' trong lớp lá? –

0

Cố gắng một câu trả lời ngắn:

self.__class__ luôn luôn là thực tế ("sub-nhất") lớp của trường hợp đối tượng của bạn - không nhất thiết phải là lớp truy nã, mà thực hiện chức năng!

Thay thế super(self.__class__, self) bằng super(__class__, self) và bạn đúng trong định nghĩa phương thức trong Python 3, vì Python 3 cung cấp biến số ma thuật __class__ cho lớp triển khai.

Và chỉ cần super() với đối số bằng không đã là lối tắt cho super(__class__, self) bằng Python 3. Xem PEP3135.

Python 2 không biết __class__ cũng như phím tắt 0 đối số super().

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