super () không thành công với lỗi: TypeError Cảnh đối số 1 phải là kiểu, không phải là classobj, khi cha mẹ không kế thừa từ đối tượng


196

Tôi nhận được một số lỗi mà tôi không thể tìm ra. Bất kỳ manh mối nào là sai với mã mẫu của tôi?

class B:
    def meth(self, arg):
        print arg

class C(B):
    def meth(self, arg):
        super(C, self).meth(arg)

print C().meth(1)

Tôi đã nhận được mã kiểm tra mẫu từ trợ giúp của phương pháp tích hợp 'siêu'.

Đây là lỗi:

Traceback (most recent call last):
  File "./test.py", line 10, in ?
    print C().meth(1)
  File "./test.py", line 8, in meth
    super(C, self).meth(arg)
TypeError: super() argument 1 must be type, not classobj

FYI, đây là sự giúp đỡ (siêu) từ chính con trăn:

Help on class super in module __builtin__:

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)
 |  Typical use to call a cooperative superclass method:
 |  class C(B):
 |      def meth(self, arg):
 |          super(C, self).meth(arg)
 |


3
Meth ?? Đó có phải là một thuật ngữ lập trình, hay ... bạn biết? Vui lòng làm rõ.
Cplusplusplus

3
@Cplusplusplus: có lẽ là viết tắt của Phương thức ;-)
ShadowFlame

Câu trả lời:


333

Vấn đề của bạn là lớp B không được khai báo là lớp "kiểu mới". Thay đổi nó như vậy:

class B(object):

và nó sẽ hoạt động.

super()và tất cả các lớp con / siêu lớp chỉ hoạt động với các lớp kiểu mới. Tôi khuyên bạn nên tập thói quen luôn gõ nó (object)trên bất kỳ định nghĩa lớp nào để đảm bảo rằng đó là một lớp kiểu mới.

Các lớp kiểu cũ (còn được gọi là các lớp "cổ điển") luôn thuộc loại classobj; các lớp học kiểu mới là loại type. Đây là lý do tại sao bạn nhận được thông báo lỗi mà bạn đã thấy:

TypeError: super() argument 1 must be type, not classobj

Hãy thử điều này để xem cho chính mình:

class OldStyle:
    pass

class NewStyle(object):
    pass

print type(OldStyle)  # prints: <type 'classobj'>

print type(NewStyle) # prints <type 'type'>

Lưu ý rằng trong Python 3.x, tất cả các lớp là kiểu mới. Bạn vẫn có thể sử dụng cú pháp từ các lớp kiểu cũ nhưng bạn có được một lớp kiểu mới. Vì vậy, trong Python 3.x bạn sẽ không gặp phải vấn đề này.


Thật thú vị, tôi đã tìm thấy vấn đề chính xác này khi chạy chai ( chaipy.org ) gây ra lỗi tương tự (TypeError: phải là loại chứ không phải classobj) chạy trên Py27 chứ không phải Py33.
tải khởi động

Trong Python 3.x, không còn các lớp "kiểu cũ" nữa. Mã sử ​​dụng khai báo "kiểu cũ" vẫn khai báo lớp "kiểu mới", do đó lỗi này không thể xảy ra trong Python 3.x.
steveha

1
Nếu lớp B không có sẵn để bạn chỉnh sửa, thì bạn phải chỉnh sửa lớp A để không cố gắng sử dụng super(); lớp A phải được tạo ra để làm việc với lớp "kiểu cũ" và có lẽ cách tốt nhất để làm điều đó là biến lớp A trở thành lớp "kiểu cũ". Tất nhiên tôi khuyên bạn chỉ nên nâng cấp toàn bộ chương trình của mình để chạy trong Python 3.x, để tất cả các lớp sẽ có kiểu mới bất kể bạn làm gì; nếu tùy chọn đó khả dụng thì đó là lựa chọn tốt nhất.
steveha

Tôi có cùng một vấn đề, nhưng lớp cơ sở của tôi được khai báo như thế nào class B(object):. Tôi đang gặp lỗi này do sử dụng @mock.patch('module.B', autospec=B)ngay trước trường hợp thử nghiệm của mình. Có bất kì ý tưởng gì để sửa chữa việc này chưa?
MikeyE

154

Ngoài ra, nếu bạn không thể thay đổi lớp B, bạn có thể sửa lỗi bằng cách sử dụng nhiều kế thừa.

class B:
    def meth(self, arg):
        print arg

class C(B, object):
    def meth(self, arg):
        super(C, self).meth(arg)

print C().meth(1)

16
Tôi không thể không để lại nhận xét, câu hỏi này nên được chấp nhận là câu trả lời 'tiêu chuẩn'.
workplaylifecycle

9
Đối với các nhân viên Google trong tương lai bị mắc kẹt trên Python 2.6: đây là câu trả lời bạn có thể muốn! Khi bạn không thể thay đổi lớp cơ sở (ví dụ: bạn đang phân lớp một lớp thư viện chuẩn), thay đổi này đối với lớp của bạn sẽ sửa siêu ().
coredumperror

Nó hoạt động tốt với tôi, bạn có thể giải thích nó hoạt động như thế nào không?
subro

@subro, điều này làm cho lớp của bạn trở thành một lớp "kiểu mới" (trong đó đối tượng lớp là loại type) trong khi vẫn phân lớp một lớp "kiểu cũ" (có đối tượng lớp là loại classobj). super()hoạt động với các lớp kiểu mới nhưng không phải với các lớp kiểu cũ.
MarSoft

câu trả lời hoàn hảo!
Tom

18

Nếu phiên bản python là 3.X thì không sao.

Tôi nghĩ phiên bản python của bạn là 2.X, siêu phẩm sẽ hoạt động khi thêm mã này

__metaclass__ = type

vì vậy mã là

__metaclass__ = type
class B:
    def meth(self, arg):
        print arg
class C(B):
    def meth(self, arg):
        super(C, self).meth(arg)
print C().meth(1)

4

Tôi cũng đã phải đối mặt với vấn đề được đăng khi tôi sử dụng python 2.7. Nó hoạt động rất tốt với python 3.4

Để làm cho nó hoạt động trong python 2.7 Tôi đã thêm __metaclass__ = typethuộc tính ở đầu chương trình của tôi và nó đã hoạt động.

__metaclass__ : Nó giúp giảm bớt sự chuyển đổi từ các lớp kiểu cũ và các lớp kiểu mới.

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.