super () ล้มเหลวด้วยข้อผิดพลาด: TypeError“ อาร์กิวเมนต์ 1 ต้องเป็นประเภทไม่ใช่ classobj” เมื่อผู้ปกครองไม่สืบทอดจากวัตถุ


196

ฉันพบข้อผิดพลาดบางอย่างที่ไม่สามารถหาได้ เบาะแสอะไรที่ผิดปกติกับรหัสตัวอย่างของฉัน?

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

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

print C().meth(1)

ฉันได้รับรหัสทดสอบตัวอย่างจากความช่วยเหลือของวิธีการในตัว 'super'

นี่คือข้อผิดพลาด:

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 นี่คือความช่วยเหลือ (super) จากไพ ธ อนเอง:

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 ?? นั่นเป็นคำที่เขียนโปรแกรมหรือ ... คุณรู้ไหม? กรุณาชี้แจง
Cplusplusplus

3
@Cplusplusplus: อาจหมายถึง Method ;-)
ShadowFlame

คำตอบ:


334

ปัญหาของคุณคือคลาส B ไม่ได้ประกาศว่าเป็นคลาส "สไตล์ใหม่" เปลี่ยนตามต้องการ:

class B(object):

และมันจะทำงาน

super()และทุกสิ่งที่ subclass / superclass ใช้งานได้กับคลาสสไตล์ใหม่เท่านั้น ฉันขอแนะนำให้คุณติดนิสัยในการพิมพ์(object)บนคำจำกัดความของคลาสใด ๆเสมอเพื่อให้แน่ใจว่าเป็นคลาสสไตล์ใหม่

เรียนแบบเก่า (ยังเป็นที่รู้จักกันเป็นชั้นเรียน "คลาสสิก") อยู่เสมอประเภทclassobj; typeการเรียนแบบใหม่เป็นประเภท นี่คือสาเหตุที่คุณได้รับข้อความแสดงข้อผิดพลาดที่คุณเห็น:

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

ลองสิ่งนี้เพื่อดูตัวคุณเอง:

class OldStyle:
    pass

class NewStyle(object):
    pass

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

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

โปรดทราบว่าใน Python 3.x คลาสทั้งหมดเป็นแบบใหม่ คุณยังคงสามารถใช้ไวยากรณ์จากคลาสแบบเก่า แต่คุณจะได้รับคลาสแบบใหม่ ดังนั้นใน Python 3.x คุณจะไม่มีปัญหานี้


ที่น่าสนใจฉันพบปัญหานี้แน่นอนที่เรียกใช้ bottle.py ( bottlepy.org ) ซึ่งมีข้อผิดพลาดคล้าย ๆ กัน (TypeError: ต้องเป็นประเภทไม่ใช่ classobj) ที่ทำงานบน Py27 แต่ไม่ใช่ Py33
bootload

ใน Python 3.x ไม่มีคลาส "แบบเก่า" อีกต่อไป โค้ดที่ใช้การประกาศ "old-style" ยังคงประกาศคลาส "new-style" ดังนั้นข้อผิดพลาดนี้ไม่สามารถเกิดขึ้นได้ใน Python 3.x
steveha

1
ถ้าชั้น B คือไม่สามารถใช้ได้สำหรับคุณที่จะแก้ไขแล้วคุณจะต้องแก้ไขระดับ A ถึงไม่ได้พยายามที่จะใช้super(); คลาส A ต้องถูกสร้างขึ้นเพื่อทำงานกับคลาส "แบบเก่า" และอาจเป็นวิธีที่ดีที่สุดในการทำคลาสนั้นให้เป็นคลาส "แบบเก่า" แน่นอนฉันขอแนะนำเพียงอัพเกรดโปรแกรมทั้งหมดของคุณให้ทำงานใน Python 3.x เพื่อให้ทุกคลาสนั้นมีรูปแบบใหม่ไม่ว่าคุณจะทำอะไร หากตัวเลือกนั้นพร้อมใช้งานมันเป็นตัวเลือกที่ดีที่สุด
steveha

ฉันมีปัญหาเดียวกัน class B(object):แต่ชั้นฐานของฉันคือการประกาศเช่น ฉันได้รับข้อผิดพลาดนี้เนื่องจากใช้@mock.patch('module.B', autospec=B)ก่อนกรณีทดสอบ มีความคิดเกี่ยวกับวิธีแก้ไขปัญหานี้อย่างไร
MikeyE

154

นอกจากนี้หากคุณไม่สามารถเปลี่ยนคลาส B คุณสามารถแก้ไขข้อผิดพลาดได้โดยใช้การสืบทอดหลายแบบ

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
ฉันไม่สามารถช่วยแสดงความคิดเห็นคนนี้ควรได้รับการยอมรับว่าเป็นคำตอบ 'มาตรฐาน'
workplaylifecycle

9
สำหรับผู้ใช้ Google ในอนาคตที่ติดอยู่ที่ Python 2.6: นี่คือคำตอบที่คุณอาจต้องการ! เมื่อคุณไม่สามารถเปลี่ยนคลาสพื้นฐาน (เช่นคุณกำลังคลาสย่อยคลาสไลบรารีมาตรฐาน) การเปลี่ยนแปลงนี้เป็นคลาสของคุณเองแก้ไข super ()
coredumperror

ทำงานได้ดีสำหรับฉันคุณช่วยอธิบายว่ามันใช้งานได้หรือไม่?
subro

@subro สิ่งนี้ทำให้คลาสของคุณเป็นคลาส "new-style" (โดยที่ class object เป็นประเภทtype) ในขณะที่ยังคงคลาสย่อยเป็นคลาส "old-style" (ซึ่งคลาสอ็อบเจ็กต์เป็นชนิดclassobj) super()ใช้งานได้กับคลาสแบบใหม่ แต่ไม่สามารถใช้กับคลาสแบบเก่าได้
MarSoft

คำตอบที่สมบูรณ์แบบ!
Tom

18

ถ้าเวอร์ชั่นของไพ ธ อนเป็น 3.X มันก็โอเค

ฉันคิดว่ารุ่นหลามของคุณคือ 2.X สุดยอดจะทำงานเมื่อเพิ่มรหัสนี้

__metaclass__ = type

ดังนั้นรหัสคือ

__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

ฉันยังประสบปัญหาโพสต์เมื่อฉันใช้ python 2.7 มันทำงานได้ดีมากกับ python 3.4

เพื่อให้ทำงานได้ใน python 2.7 ฉันได้เพิ่ม__metaclass__ = typeคุณสมบัติที่ด้านบนของโปรแกรมและใช้งานได้

__metaclass__ : ช่วยลดการเปลี่ยนจากคลาสแบบเก่าและคลาสแบบใหม่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.