Python super () เพิ่ม TypeError


109

ใน Python 2.5 โค้ดต่อไปนี้ทำให้เกิด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

ถ้าฉันแทนที่class Xด้วยclass X(object)มันจะทำงาน คำอธิบายสำหรับเรื่องนี้คืออะไร?


3
"อย่างไรก็ตามฉันแทนที่คลาส X ด้วยคลาส X (อ็อบเจ็กต์)" ของคุณแก้ไขปัญหาของฉันได้! thanx
AliBZ

คำตอบ:


132

เหตุผลก็คือsuper()ดำเนินการในคลาสสไตล์ใหม่เท่านั้นซึ่งในซีรีย์ 2.x หมายถึงการขยายจาก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
สิ่งนี้กลายเป็นพฤติกรรมเริ่มต้นจาก python เวอร์ชันใด
Geo

6
2.2 คือเมื่อมีการเปิดตัวคลาสรูปแบบใหม่ 3.0 คือที่ที่พวกเขากลายเป็นค่าเริ่มต้น
Cody Brocious

7
@tsunami ถ้าอยากได้ซุปเปอร์คลาสทำ "Xa (self)"
James Brady

ฉันคิดว่าคุณเข้าใจฉันผิด อันมีค่า. ฉันจำได้ว่าฉันใช้ python เวอร์ชันที่น้อยกว่า 3.0 และฉันไม่ได้บอกเป็นพิเศษว่าคลาสของฉันสืบทอดมาจาก Object และการเรียกใช้งานขั้นสูง อาจจะเป็นพฤติกรรมเริ่มต้นจาก 2.6? แค่บอกว่า :)
Geo

Alabaster ไม่จำเป็นจริงๆสำหรับสิ่งนั้น ชั้นเรียนรูปแบบใหม่มีสิทธิประโยชน์มากมายไม่ใช่แค่ขั้นสูงเท่านั้น ไม่ควรส่งเสริมวิธีการแบบเก่า
Cody Brocious

14

นอกจากนี้อย่าใช้ super () เว้นแต่คุณจะต้อง ไม่ใช่ "สิ่งที่ถูกต้อง" โดยทั่วไปสำหรับคลาสรูปแบบใหม่ที่คุณอาจสงสัย

มีหลายครั้งที่คุณคาดหวังว่าจะได้รับมรดกหลายครั้งและคุณอาจต้องการมัน แต่จนกว่าคุณจะรู้รายละเอียดที่มีขนดกของ MRO คุณควรปล่อยมันไว้คนเดียวและปฏิบัติตาม:

 X.a(self)

2
ถูกต้องหรือไม่เพราะในช่วง 6 เดือนของ Python / Django ฉันใช้ super เป็น "สิ่งที่ถูกต้องทั่วไปที่ต้องทำ"
philgo20

1
มันไม่ได้ทำร้ายคุณสำหรับการสืบทอดเพียงครั้งเดียวในตัวมันเอง (ยกเว้นว่ามันช้ากว่าเล็กน้อย) แต่มันก็ไม่ได้รับอะไรเลยด้วยตัวมันเอง คุณต้องออกแบบวิธีการใด ๆ ที่ต้องใช้การสืบทอดแบบทวีคูณ (โดยเฉพาะอย่างยิ่ง__init__) เพื่อส่งผ่านข้อโต้แย้งด้วยวิธีที่สะอาดและสมเหตุสมผลมิฉะนั้นคุณจะได้รับ TypeErrors หรือปัญหาการดีบักที่แย่กว่าเมื่อมีคนพยายามทวีคูณการสืบทอดโดยใช้คลาสของคุณ หากคุณไม่ได้ออกแบบมาเพื่อรองรับ MI ด้วยวิธีนี้จริงๆ (ซึ่งค่อนข้างยุ่งยาก) อาจเป็นการดีกว่าที่จะหลีกเลี่ยงความหมายsuperที่ว่าวิธีนี้ปลอดภัยจาก MI
Bobince

3

ในกรณีที่ไม่มีคำตอบข้างต้นที่กล่าวถึงอย่างชัดเจน คลาสพาเรนต์ของคุณจำเป็นต้องสืบทอดจาก "อ็อบเจกต์" ซึ่งโดยพื้นฐานแล้วจะเปลี่ยนเป็นคลาสสไตล์ใหม่

# 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

ขออภัยใน Python 3.x ตัวอย่างที่สองของคุณ (การสืบทอดโดยนัย) ไม่สามารถใช้งานได้จริงในบริบทของปัญหาที่กล่าวถึง
โซโฟร

1

ฉันลองใช้วิธี Xa () ต่างๆ อย่างไรก็ตามดูเหมือนว่าพวกเขาต้องการอินสแตนซ์ของ X เพื่อดำเนินการ a () ดังนั้นฉันจึงทำ X () a (self) ซึ่งดูเหมือนจะสมบูรณ์กว่าคำตอบก่อนหน้านี้อย่างน้อยก็สำหรับแอปพลิเคชันที่ฉันพบ ดูเหมือนจะไม่ใช่วิธีที่ดีในการจัดการปัญหาเนื่องจากมีการก่อสร้างและการทำลายที่ไม่จำเป็น แต่ก็ใช้ได้ดี

แอปพลิเคชันเฉพาะของฉันคือโมดูล cmd.Cmd ของ Python ซึ่งเห็นได้ชัดว่าไม่ใช่วัตถุ NewStyle ด้วยเหตุผลบางประการ

ผลลัพธ์สุดท้าย:

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