Python super () tăng TypeError


109

Trong Python 2.5, đoạn mã sau tạo ra TypeError:

>>> class X:
      def a(self):
        print "a"

>>> class Y(X):
      def a(self):
        super(Y,self).a()
        print "b"

>>> c = Y()
>>> c.a()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in a
TypeError: super() argument 1 must be type, not classobj

Nếu tôi thay thế class Xbằng class X(object), nó sẽ hoạt động. Lời giải thích cho điều này là gì?


3
của bạn "tuy nhiên tôi thay thế lớp X bằng lớp X (đối tượng)" đã khắc phục sự cố của tôi! thanx
AliBZ

Câu trả lời:


132

Lý do là nó super()chỉ hoạt động trên các lớp kiểu mới , trong chuỗi 2.x có nghĩa là mở rộng từ object:

>>> class X(object):
        def a(self):
            print 'a'

>>> class Y(X):
        def a(self):
            super(Y, self).a()
            print 'b'

>>> c = Y()
>>> c.a()
a
b

4
Từ phiên bản python nào, điều này đã trở thành hành vi mặc định?
Geo

6
2.2 là khi các lớp kiểu mới được giới thiệu, 3.0 là nơi chúng trở thành mặc định.
Cody Brocious

7
@tsunami nếu bạn muốn đạt hạng cao nhất, hãy làm "Xa (tự)"
James Brady

Tôi nghĩ bạn đã hiểu lầm tôi . Chân máy. Tôi nhớ rằng tôi đang sử dụng phiên bản python nhỏ hơn 3.0 và tôi không nói cụ thể rằng lớp của tôi kế thừa từ Object và lệnh gọi siêu hoạt động. Có thể đó là hành vi mặc định từ 2.6? Chỉ cần nói :)
Geo

Alabaster, thực sự không cần điều đó. Các lớp học kiểu mới có rất nhiều lợi ích, không chỉ là siêu. Những cách kiểu cũ không nên được quảng bá.
Cody Brocious

14

Ngoài ra, không sử dụng super () trừ khi bạn phải làm như vậy. Đó không phải là mục đích chung "điều đúng đắn" để làm với các lớp kiểu mới mà bạn có thể nghi ngờ.

Đôi khi bạn đang mong đợi đa thừa kế và bạn có thể muốn nó, nhưng cho đến khi bạn biết những thông tin chi tiết về MRO, tốt nhất hãy để nó yên và kiên trì:

 X.a(self)

2
điều đó có chính xác không vì trong 6 tháng sử dụng Python / Django, tôi đã sử dụng super như là "điều đúng đắn chung cần làm"?
philgo20

1
Chà, bản thân nó không làm hại bạn vì thừa kế đơn lẻ (ngoại trừ việc nó chậm hơn một chút), nhưng nó cũng không giúp bạn có được gì cả. Bạn phải thiết kế bất kỳ phương thức nào cần nhân-thừa kế (đáng chú ý nhất __init__) để chuyển qua các đối số một cách rõ ràng và hợp lý, nếu không bạn sẽ gặp phải lỗi TypeErrors hoặc tệ hơn là các vấn đề gỡ lỗi khi ai đó cố gắng nhân-thừa kế bằng cách sử dụng lớp của bạn. Trừ khi bạn thực sự thiết kế để hỗ trợ MI theo cách này (khá phức tạp), có lẽ tốt hơn hết bạn nên tránh ngụ ý superrằng phương pháp này an toàn cho MI.
bobince

3

Trong trường hợp không có câu trả lời nào ở trên đề cập rõ ràng. Lớp cha của bạn cần kế thừa từ "object", về cơ bản sẽ biến nó thành một lớp kiểu mới.

# python 3.x:
class ClassName(object): # This is a new style class
    pass

class ClassName: # This is also a new style class ( implicit inheritance from object )
    pass

# Python 2.x:
class ClassName(object): # This is a new style class
    pass

class ClassName:         # This is a old style class
    pass

Xin lỗi, nhưng trong Python 3.x, ví dụ thứ hai của bạn (kế thừa ngầm định) không thực sự hoạt động trong bối cảnh vấn đề được đề cập.
sophros

1

Tôi đã thử các phương thức Xa () khác nhau; tuy nhiên, họ dường như yêu cầu một thể hiện của X để thực hiện một (), vì vậy tôi đã thực hiện X (). a (self), có vẻ đầy đủ hơn các câu trả lời trước đó, ít nhất là đối với các ứng dụng tôi đã gặp. Đây có vẻ không phải là cách tốt để xử lý vấn đề vì có xây dựng và phá hủy không cần thiết, nhưng nó hoạt động tốt.

Ứng dụng cụ thể của tôi là mô-đun cmd.Cmd của Python, rõ ràng không phải là một đối tượng NewStyle vì một số lý do.

Kết quả cuối cùng:

X().a(self)
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.