2012-05-07 33 views
57

Nguyên Tôi muốn hỏi this question, nhưng sau đó tôi thấy nó đã được nghĩ đến trước đây ...Python mở rộng với - sử dụng siêu() Python 3 vs Python 2

Googling xung quanh tôi thấy ví dụ này của extending configparser. Các công trình sau đây với Python 3:

$ python3 
Python 3.2.3rc2 (default, Mar 21 2012, 06:59:51) 
[GCC 4.6.3] on linux2 
>>> from configparser import SafeConfigParser 
>>> class AmritaConfigParser(SafeConfigParser): 
...  def __init_(self): 
...   super().__init__() 
... 
>>> cfg = AmritaConfigParser() 

Nhưng không phải với Python 2:

>>> class AmritaConfigParser(SafeConfigParser): 
...  def __init__(self): 
...   super(SafeConfigParser).init() 
... 
>>> cfg = AmritaConfigParser() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 3, in __init__ 
TypeError: must be type, not classob 

Sau đó, tôi đọc một chút về Python New Class vs phong cách Old Class (ví dụ here Và bây giờ tôi. là băn khoăn, tôi có thể làm:

class MyConfigParser(ConfigParser.ConfigParser): 
     def Write(self, fp): 
      """override the module's original write funcition""" 
      .... 
     def MyWrite(self, fp): 
      """Define new function and inherit all others""" 

Nhưng, tôi không nên gọi init đây có phải là bằng Python 2 tương đương với:

012.351.
class AmritaConfigParser(ConfigParser.SafeConfigParser): 
    #def __init__(self): 
    # super().__init__() # Python3 syntax, or rather, new style class syntax ... 
    # 
    # is this the equivalent of the above ? 
    def __init__(self): 
     ConfigParser.SafeConfigParser.__init__(self) 
+1

Trong ví dụ của bạn, bạn không cần phải xác định một '__init __() 'trong subclass nếu tất cả nó làm là gọi lớp siêu' __init __() '(trong hoặc Python 2 hoặc 3) - thay vì chỉ để cho siêu được kế thừa. – martineau

+0

Tham khảo hữu ích: http://amyboyle.ninja/Python-Inheritance/ –

Trả lời

99
  • super() (không có đối số) đã được giới thiệu trong Python 3 (cùng với __class__):

    super() -> same as super(__class__, self) 
    

    do đó sẽ là Python 2 tương đương cho các lớp học kiểu mới:

    super(CurrentClass, self) 
    
  • cho các lớp học kiểu cũ bạn luôn có thể sử dụng:

    class Classname(OldStyleParent): 
        def __init__(self, *args, **kwargs): 
         OldStyleParent.__init__(self, *args, **kwargs) 
    
+1

-1. Câu trả lời này không làm rõ bất cứ điều gì cho tôi. Trong Python 2, 'super (__ class __)' cho 'NameError: tên toàn cục '__class__' không được định nghĩa', và' super (self .__ class __) 'cũng sai. Bạn * phải * cung cấp một thể hiện như là một đối số thứ hai, mà sẽ đề nghị bạn cần phải làm 'siêu (self .__ class__, self)', nhưng đó là ** sai **. Nếu 'Class2' kế thừa từ' Class1' và 'Class1' các cuộc gọi' siêu (tự.__class__, self) .__ init __() ',' '' '' '' 'của lớp1 sẽ tự gọi * khi khởi tạo một thể hiện' Class2'. – jpmc26

+0

Để làm rõ một điểm, tôi nhận 'TypeError: super() lấy ít nhất 1 đối số (0 đã cho)' khi cố gắng gọi 'super (self .__ class __)' trong Python 2. (Điều này không có ý nghĩa gì nhiều , nhưng nó thể hiện số lượng thông tin bị thiếu trong câu trả lời này.) – jpmc26

+2

@ jpmc26: trong python2 bạn nhận được lỗi này vì bạn đang cố gắng gọi '__init __()' mà không có đối số trên đối tượng siêu liên kết (mà bạn nhận được bằng cách gọi 'super (self .__ class __) 'chỉ với một đối số), bạn cần một đối tượng siêu liên kết thì nó sẽ hoạt động:' super (CurrentClass, self) .__ init __() '. Không sử dụng 'self .__ class__' vì nó sẽ luôn tham chiếu đến lớp _same_ khi gọi một phụ huynh và therfore tạo một vòng lặp vô hạn nếu cha mẹ đó cũng làm như vậy. – mata

28

Trong một trường hợp thừa kế duy nhất (khi bạn chỉ phân lớp một lớp), lớp mới của bạn kế thừa các phương thức của lớp cơ sở. Điều này bao gồm __init__. Vì vậy, nếu bạn không xác định nó trong lớp học của bạn, bạn sẽ nhận được một từ cơ sở.

Mọi thứ trở nên phức tạp nếu bạn giới thiệu nhiều thừa kế (phân lớp nhiều hơn một lớp tại một thời điểm). Điều này là do nếu có nhiều hơn một lớp cơ sở có __init__, lớp của bạn sẽ chỉ thừa kế lớp đầu tiên.

Trong trường hợp này, bạn thực sự nên sử dụng super nếu có thể, tôi sẽ giải thích lý do. Nhưng không phải lúc nào bạn cũng có thể. Vấn đề là tất cả các lớp cơ sở của bạn cũng phải sử dụng nó (và các lớp cơ sở của chúng cũng như toàn bộ cây).

Nếu đúng như vậy, thì đây cũng sẽ làm việc một cách chính xác (bằng Python 3 nhưng bạn có thể làm lại nó vào Python 2 - nó cũng có super):

class A: 
    def __init__(self): 
     print('A') 
     super().__init__() 

class B: 
    def __init__(self): 
     print('B') 
     super().__init__() 

class C(A, B): 
    pass 

C() 
#prints: 
#A 
#B 

Thông báo như thế nào cả hai lớp cơ sở sử dụng super mặc dù họ không có các lớp cơ sở riêng của họ.

Điều gì super có nghĩa là: nó gọi phương thức từ lớp tiếp theo trong MRO (thứ tự phân giải phương pháp). MRO cho C là: (C, A, B, object). Bạn có thể in C.__mro__ để xem.

Vì vậy, C thừa hưởng __init__ từ Asuper trong A.__init__ cuộc gọi B.__init__ (B sau A trong MRO).

Vì vậy, bằng cách không làm gì trong số C, bạn sẽ gọi cả hai, đó là những gì bạn muốn.

Bây giờ nếu bạn không sử dụng super, bạn sẽ kết thúc kế thừa A.__init__ (như trước) nhưng lần này không có gì gọi là B.__init__ cho bạn.

class A: 
    def __init__(self): 
     print('A') 

class B: 
    def __init__(self): 
     print('B') 

class C(A, B): 
    pass 

C() 
#prints: 
#A 

Để khắc phục điều đó, bạn phải xác định C.__init__:

class C(A, B): 
    def __init__(self): 
     A.__init__(self) 
     B.__init__(self) 

Vấn đề với điều đó là trong cây MI phức tạp hơn, __init__ phương pháp của một số lớp học có thể kết thúc được gọi là nhiều hơn một lần trong khi siêu/MRO đảm bảo rằng họ được gọi một lần.

+7

'Lưu ý cách cả hai lớp cơ sở sử dụng siêu mặc dù chúng không có lớp cơ sở riêng của chúng.’ Chúng có. Trong py3k mọi lớp con của đối tượng. – akaRem

15

Tóm lại, chúng tương đương nhau. Chúng ta hãy xem lịch sử:

(1) lúc đầu, chức năng trông như thế này.

class MySubClass(MySuperClass): 
     def __init__(self): 
      MySuperClass.__init__(self) 

(2) để làm cho mã trừu tượng hơn (và di động hơn). Một phương pháp phổ biến để có được Super-Class được phát minh như:

super(<class>, <instance>) 

Và hàm init có thể là:

class MySubClassBetter(MySuperClass): 
     def __init__(self): 
      super(MySubClassBetter, self).__init__() 

Tuy nhiên đòi hỏi phải có một qua rõ ràng của cả lớp và dụ phá vỡ DRY (Do not Lặp lại chính mình) quy tắc một chút.

(3) trong V3. Thông minh hơn,

super() 

là đủ trong hầu hết trường hợp. Bạn có thể tham khảo http://www.python.org/dev/peps/pep-3135/

0

Chỉ cần có một ví dụ đơn giản và đầy đủ cho Python 3, mà hầu hết mọi người dường như đang sử dụng ngay bây giờ.

class MySuper(object): 
    def __init__(self,a): 
     self.a = a 

class MySub(MySuper): 
    def __init__(self,a,b): 
     self.b = b 
     super().__init__(a) 

my_sub = MySub(42,'chickenman') 
print(my_sub.a) 
print(my_sub.b) 

cho

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