super () kończy się niepowodzeniem z błędem: TypeError „argument 1 musi być typem, a nie classobj”, gdy rodzic nie dziedziczy po obiekcie

196

Mam błąd, którego nie mogę zrozumieć. Masz jakieś pojęcie, co jest nie tak z moim przykładowym kodem?

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

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

print C().meth(1)

Otrzymałem przykładowy kod testowy z pomocą wbudowanej metody „super”.

Oto błąd:

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

Do Twojej wiadomości, oto pomoc (super) samego Pythona:

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
źródło
możliwy duplikat Python super () podnosi błąd typu! Czemu?
użytkownik
3
Meth Czy to termin programowania, czy ... wiesz? Proszę o wyjaśnienie.
Cplusplusplus
3
@Cplusplusplus: prawdopodobnie oznacza Metodę ;-)
ShadowFlame

Odpowiedzi:

333

Problem polega na tym, że klasa B nie została zadeklarowana jako klasa „nowego stylu”. Zmień to tak:

class B(object):

i zadziała.

super()i wszystkie elementy podklasy / superklasy działają tylko z klasami w nowym stylu. Zalecam, abyś przyzwyczaił się zawsze wpisywać to (object)w dowolnej definicji klasy, aby mieć pewność, że jest to klasa nowego stylu.

Klasy w starym stylu (znane również jako klasy „klasyczne”) są zawsze typu classobj; klasy w nowym stylu są typu type. Oto dlaczego zobaczyłeś komunikat o błędzie:

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

Spróbuj tego, aby przekonać się sam:

class OldStyle:
    pass

class NewStyle(object):
    pass

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

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

Zauważ, że w Pythonie 3.x wszystkie klasy są w nowym stylu. Nadal możesz używać składni z klas starego stylu, ale otrzymujesz klasę nowego stylu. Tak więc w Pythonie 3.x nie będziesz mieć tego problemu.

steveha
źródło
interesujące, znalazłem ten właśnie problem z uruchomieniem bottle.py ( bottlepy.org ), który generuje podobny błąd (TypeError: must be type, not classobj) działający na Py27, ale nie Py33.
bootload
W Pythonie 3.x nie ma już klas „w starym stylu”. Kod korzystający z deklaracji „starego stylu” nadal deklaruje klasę „nowego stylu”, więc ten błąd nie może wystąpić w Pythonie 3.x.
steveha
1
Jeśli klasa B nie jest dostępna do edycji, musisz edytować klasę A, aby nie próbować jej używać super(); klasa A musi być przystosowana do pracy z klasą „w starym stylu”, a być może najlepszym sposobem na to byłoby uczynienie klasy A samą klasą „w starym stylu”. Oczywiście polecam uaktualnienie całego programu do działania w Pythonie 3.x, aby wszystkie klasy miały nowy styl bez względu na to, co robisz; jeśli ta opcja jest dostępna, jest to najlepsza opcja.
steveha,
Mam ten sam problem, ale moja podstawowa klasa jest zadeklarowana jako class B(object):. Otrzymuję ten błąd z powodu użycia @mock.patch('module.B', autospec=B)tuż przed moim przypadkiem testowym. Wszelkie przemyślenia, jak to naprawić?
MikeyE,
154

Ponadto, jeśli nie możesz zmienić klasy B, możesz naprawić błąd, używając wielokrotnego dziedziczenia.

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
źródło
16
Nie mogłem pomóc w pozostawieniu komentarza, ten należy zaakceptować jako „standardową” odpowiedź.
cykl roboczy,
9
Dla przyszłych pracowników Google, którzy utknęli w Pythonie 2.6: jest to odpowiedź, której prawdopodobnie chcesz! Kiedy nie możesz zmienić klasy podstawowej (np. Podklasujesz klasę biblioteki standardowej), ta zmiana na własną klasę naprawia super ().
coredumperror
Działa mi to dobrze. Czy ktoś może wyjaśnić, jak to działa?
subro
@ subro, to sprawia, że ​​twoja klasa jest klasą „nowego stylu” (gdzie obiekt klasy jest typu type), a jednocześnie podklasuje klasę „starego stylu” (której obiekt klasy jest typu classobj). super()działa z klasami w nowym stylu, ale nie z klasami w starym stylu.
MarSoft,
idealna odpowiedź!
Tom
18

Jeśli wersja Pythona to 3.X, jest w porządku.

Myślę, że twoja wersja Pythona to 2.X, super działałoby podczas dodawania tego kodu

__metaclass__ = type

więc kod jest

__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
źródło
4

Wystąpił również problem z opublikowanym problemem, gdy korzystałem z Pythona 2.7. Działa bardzo dobrze z Pythonem 3.4

Aby działał w Pythonie 2.7, dodałem __metaclass__ = typeatrybut u góry mojego programu i działał.

__metaclass__ : Ułatwia przejście z klas w starym stylu do klas w nowym stylu.

JON
źródło