super () schlägt mit Fehler fehl: TypeError "Argument 1 muss Typ sein, nicht classobj", wenn Eltern nicht vom Objekt erben

196

Ich erhalte einen Fehler, den ich nicht herausfinden kann. Gibt es einen Hinweis darauf, was mit meinem Beispielcode nicht stimmt?

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

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

print C().meth(1)

Ich habe den Beispieltestcode mithilfe der integrierten 'Super'-Methode erhalten.

Hier ist der Fehler:

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

Zu Ihrer Information, hier ist die Hilfe (super) von Python selbst:

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
quelle
Mögliches Duplikat von Python Super () löst TypeError aus! Warum?
Benutzer
3
Meth ?? Ist das ein Programmierbegriff oder ... weißt du? Bitte klären Sie.
Cplusplusplus
3
@Cplusplusplus: steht wahrscheinlich für Methode ;-)
ShadowFlame

Antworten:

333

Ihr Problem ist, dass Klasse B nicht als "New-Style" -Klasse deklariert ist. Ändere es so:

class B(object):

und es wird funktionieren.

super()und alle Sachen der Unterklasse / Oberklasse funktionieren nur mit Klassen neuen Stils. Ich empfehle Ihnen, sich daran zu gewöhnen, dies immer (object)in eine Klassendefinition einzugeben, um sicherzustellen, dass es sich um eine Klasse neuen Stils handelt.

Klassen alten Stils (auch als "klassische" Klassen bekannt) sind immer vom Typ classobj; Klassen neuen Stils sind vom Typ type. Aus diesem Grund haben Sie die folgende Fehlermeldung erhalten:

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

Versuchen Sie dies, um sich selbst davon zu überzeugen:

class OldStyle:
    pass

class NewStyle(object):
    pass

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

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

Beachten Sie, dass in Python 3.x alle Klassen im neuen Stil sind. Sie können weiterhin die Syntax der Klassen im alten Stil verwenden, erhalten jedoch eine Klasse im neuen Stil. In Python 3.x tritt dieses Problem also nicht auf.

steveha
quelle
Interessant, ich fand genau dieses Problem beim Ausführen von Bottle.py ( Bottlepy.org ), das einen ähnlichen Fehler (TypeError: muss Typ sein, nicht Classobj) auslöst, der auf Py27, aber nicht auf Py33 ausgeführt wird.
Bootload
In Python 3.x gibt es keine "alten" Klassen mehr. Code, der die Deklaration "alten Stils" verwendet, deklariert weiterhin eine Klasse "neuen Stils", sodass dieser Fehler in Python 3.x nicht auftreten kann.
Steveha
1
Wenn Klasse B nicht zum Bearbeiten verfügbar ist, müssen Sie Klasse A bearbeiten, um nicht zu versuchen, sie zu verwenden super(). Klasse A muss dazu gebracht werden, mit einer "alten" Klasse zu arbeiten, und möglicherweise ist der beste Weg, dies zu tun, Klasse A selbst zu einer "alten" Klasse zu machen. Natürlich empfehle ich, nur Ihr gesamtes Programm für die Ausführung in Python 3.x zu aktualisieren, damit alle Klassen unabhängig von Ihrer Tätigkeit einen neuen Stil erhalten. Wenn diese Option verfügbar ist, ist sie die beste Option.
Steveha
Ich habe das gleiche Problem, aber meine Basisklasse wird wie folgt deklariert class B(object):. Ich erhalte diesen Fehler aufgrund der Verwendung @mock.patch('module.B', autospec=B)kurz vor meinem Testfall. Irgendwelche Gedanken darüber, wie man das behebt?
MikeyE
154

Wenn Sie Klasse B nicht ändern können, können Sie den Fehler mithilfe der Mehrfachvererbung beheben.

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
quelle
16
Ich konnte nicht anders, als einen Kommentar zu hinterlassen. Dieser sollte als "Standard" -Antwort akzeptiert werden.
Workplaylifecycle
9
Für zukünftige Googler, die an Python 2.6 festhalten: Dies ist die Antwort, die Sie wahrscheinlich wollen! Wenn Sie die Basisklasse nicht ändern können (z. B. wenn Sie eine Standardbibliotheksklasse unterordnen), behebt diese Änderung an Ihrer eigenen Klasse super ().
Coredumperror
Es hat gut funktioniert für mich. Kannst du jemandem erklären, wie es funktioniert?
Subro
@subro, dies macht Ihre Klasse zu einer Klasse im "neuen Stil" (wobei das Klassenobjekt vom Typ ist type), während dennoch eine Klasse im "alten Stil" (deren Klassenobjekt vom Typ ist classobj) untergeordnet wird . super()funktioniert mit Klassen neuen Stils, jedoch nicht mit Klassen alten Stils.
MarSoft
perfekte Antwort!
Tom
18

Wenn die Python-Version 3.X ist, ist es in Ordnung.

Ich denke, Ihre Python-Version ist 2.X, das Super würde funktionieren, wenn Sie diesen Code hinzufügen

__metaclass__ = type

so ist der Code

__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
quelle
4

Ich war auch mit dem veröffentlichten Problem konfrontiert, als ich Python 2.7 verwendete. Es funktioniert sehr gut mit Python 3.4

Damit es in Python 2.7 funktioniert, habe ich das __metaclass__ = typeAttribut oben in meinem Programm hinzugefügt und es hat funktioniert.

__metaclass__ : Es erleichtert den Übergang von Klassen alten und neuen Klassen.

JON
quelle