Python super () memunculkan TypeError

109

Di Python 2.5, kode berikut memunculkan a 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

Jika saya mengganti class Xdengan class X(object), itu akan berhasil. Apa penjelasannya untuk ini?

Geo
sumber
3
"Namun saya mengganti kelas X dengan kelas X (objek)" Anda memperbaiki masalah saya! thanx
AliBZ

Jawaban:

132

Alasannya adalah itu super()hanya beroperasi pada kelas gaya baru , yang dalam seri 2.x berarti meluas dari 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
Cody Brocious
sumber
4
Dari versi python apa ini menjadi perilaku default?
Geo
6
2.2 adalah saat kelas gaya baru diperkenalkan, 3.0 adalah tempat mereka menjadi default.
Cody Brocious
7
@tsunami jika Anda ingin mendapatkan superclass, lakukan "Xa (self)"
James Brady
Saya pikir Anda salah paham. Triptych. Saya ingat saya menggunakan versi python kurang dari 3.0, dan saya tidak secara khusus mengatakan bahwa kelas saya mewarisi dari Object, dan panggilan ke super berfungsi. Mungkin itu perilaku default dari 2.6? Hanya mengatakan :)
Geo
Alabaster, sebenarnya tidak perlu itu. Kelas gaya baru memiliki banyak manfaat, bukan hanya super. Cara gaya lama tidak boleh dipromosikan.
Cody Brocious
14

Selain itu, jangan gunakan super () kecuali Anda harus melakukannya. Bukan tujuan umum "hal yang benar" untuk dilakukan dengan kelas gaya baru yang mungkin Anda curigai.

Ada kalanya Anda mengharapkan banyak warisan dan Anda mungkin menginginkannya, tetapi sampai Anda mengetahui detail berbulu dari MRO, sebaiknya biarkan saja dan tetap berpegang pada:

 X.a(self)
bobince
sumber
2
apakah itu benar karena dalam 6 bulan saya Python / Django saya telah menggunakan super sebagai "hal umum yang benar untuk dilakukan"?
philgo20
1
Yah, tidak ada salahnya Anda untuk warisan tunggal itu sendiri (kecuali bahwa itu sedikit lebih lambat), tetapi Anda juga tidak mendapatkan apa-apa dengan sendirinya. Anda harus mendesain metode apa pun yang perlu multiply-inherit (terutama __init__) untuk melewati argumen dengan cara yang bersih dan masuk akal, jika tidak, Anda akan mendapatkan TypeErrors atau masalah debugging yang lebih buruk ketika seseorang mencoba multiply-inherit menggunakan kelas Anda. Kecuali jika Anda benar-benar merancang untuk mendukung MI dengan cara ini (yang cukup rumit), mungkin lebih baik untuk menghindari implikasi superbahwa metode ini aman untuk MI.
bobince
3

Seandainya tidak ada jawaban di atas yang disebutkan dengan jelas. Kelas induk Anda perlu mewarisi dari "object", yang pada dasarnya akan mengubahnya menjadi kelas gaya baru.

# 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
Abhi Tk
sumber
Maaf, tetapi dengan Python 3.x contoh kedua Anda (warisan implisit) tidak benar-benar berfungsi dalam konteks masalah yang disebutkan.
sophros
1

Saya mencoba berbagai metode Xa (); Namun, mereka tampaknya memerlukan sebuah instance dari X untuk melakukan a (), jadi saya melakukan X (). a (self), yang tampaknya lebih lengkap dari jawaban sebelumnya, setidaknya untuk aplikasi yang saya temui. Tampaknya ini bukan cara yang baik untuk menangani masalah karena ada konstruksi dan penghancuran yang tidak perlu, tetapi berfungsi dengan baik.

Aplikasi khusus saya adalah modul cmd.Cmd Python, yang ternyata bukan objek NewStyle karena alasan tertentu.

Hasil Akhir:

X().a(self)
weberc2.dll
sumber