super () gagal dengan kesalahan: TypeError "argumen 1 harus mengetik, bukan classobj" ketika orangtua tidak mewarisi dari objek

196

Saya mendapatkan beberapa kesalahan yang saya tidak tahu. Adakah petunjuk apa yang salah dengan kode sampel saya?

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

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

print C().meth(1)

Saya mendapat kode uji sampel dari bantuan metode bawaan 'super'.

Inilah kesalahannya:

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, ini adalah bantuan (super) dari python itu sendiri:

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)
 |
Ehsan Foroughi
sumber
3
Meth ?? Apakah itu istilah pemrograman, atau ... kau tahu? Mohon klarifikasi.
Cplusplusplus
3
@Cplusplusplus: mungkin singkatan dari Metode ;-)
ShadowFlame

Jawaban:

333

Masalah Anda adalah bahwa kelas B tidak dinyatakan sebagai kelas "gaya baru". Ubah seperti ini:

class B(object):

dan itu akan berhasil.

super()dan semua hal-hal subkelas / superclass hanya berfungsi dengan kelas gaya baru. Saya sarankan Anda membiasakan diri selalu mengetik (object)pada definisi kelas apa pun untuk memastikan itu adalah kelas gaya baru.

Kelas gaya lama (juga dikenal sebagai kelas "klasik") selalu bertipe classobj; kelas gaya baru adalah tipe type. Inilah mengapa Anda mendapatkan pesan kesalahan yang Anda lihat:

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

Coba ini untuk melihat sendiri:

class OldStyle:
    pass

class NewStyle(object):
    pass

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

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

Perhatikan bahwa dalam Python 3.x, semua kelas adalah gaya baru. Anda masih bisa menggunakan sintaks dari kelas gaya lama tetapi Anda mendapatkan kelas gaya baru. Jadi, dalam Python 3.x Anda tidak akan memiliki masalah ini.

steveha
sumber
menarik, saya menemukan masalah yang tepat ini menjalankan bottle.py ( bottlepy.org ) yang melempar kesalahan serupa (TypeError: harus mengetik, bukan classobj) berjalan pada Py27 tetapi tidak Py33.
bootload
Di Python 3.x, tidak ada lagi kelas "gaya lama". Kode yang menggunakan deklarasi "gaya lama" masih mendeklarasikan kelas "gaya baru", jadi kesalahan ini tidak dapat terjadi di Python 3.x.
steveha
1
Jika kelas B tidak tersedia untuk Anda edit, maka Anda harus mengedit kelas A untuk tidak mencoba menggunakan super(); kelas A harus dibuat untuk bekerja dengan kelas "gaya lama", dan mungkin cara terbaik untuk melakukannya adalah membuat kelas A menjadi kelas "gaya lama". Tentu saja saya sarankan hanya meningkatkan seluruh program Anda untuk berjalan di Python 3.x, sehingga semua kelas akan menjadi gaya baru apa pun yang Anda lakukan; jika opsi itu tersedia itu adalah pilihan terbaik.
steveha
Saya memiliki masalah yang sama, tetapi kelas dasar saya dinyatakan seperti class B(object):. Saya mendapatkan kesalahan ini karena menggunakan @mock.patch('module.B', autospec=B)sebelum test case saya. Adakah pemikiran tentang cara memperbaikinya?
MikeyE
154

Juga, jika Anda tidak dapat mengubah kelas B, Anda dapat memperbaiki kesalahan dengan menggunakan beberapa pewarisan.

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)
frmdstryr
sumber
16
Saya tidak dapat membantu untuk meninggalkan komentar, yang ini harus diterima sebagai jawaban 'standar'.
workplaylifecycle
9
Untuk googler masa depan yang terjebak pada Python 2.6: ini adalah jawaban yang mungkin Anda inginkan! Saat Anda tidak dapat mengubah kelas dasar (mis. Anda mensubklasifikasikan kelas perpustakaan standar), perubahan ini untuk kelas Anda sendiri akan memperbaiki super ().
coredumperror
Itu bekerja dengan baik untuk saya, dapatkah Anda menjelaskan bagaimana cara kerjanya?
subro
@ Subro, ini membuat kelas Anda kelas "gaya baru" (di mana objek kelas bertipe type) sementara masih subkelas kelas "gaya lama" (objek kelasnya bertipe classobj). super()bekerja dengan kelas gaya baru tetapi tidak dengan kelas gaya lama.
MarSoft
jawaban sempurna!
Tom
18

Jika versi python adalah 3.X, tidak apa-apa.

Saya pikir versi python Anda adalah 2.X, super akan bekerja ketika menambahkan kode ini

__metaclass__ = type

jadi kodenya

__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)
yanghaogn
sumber
4

Saya juga dihadapkan dengan masalah yang diposting ketika saya menggunakan python 2.7. Ini bekerja sangat baik dengan python 3.4

Untuk membuatnya bekerja di python 2.7 Saya telah menambahkan __metaclass__ = typeatribut di bagian atas program saya dan itu berhasil.

__metaclass__ : Ini memudahkan transisi dari kelas gaya lama dan kelas gaya baru.

JON
sumber