Python super () wywołuje błąd TypeError

109

W Pythonie 2.5 poniższy kod wywołuje 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

Gdybym wymienić class Xz class X(object), to będzie działać. Jakie jest tego wytłumaczenie?

Geo
źródło
3
Twoje „jednak zamieniam klasę X na klasę X (obiekt)” rozwiązało mój problem! thanx
AliBZ

Odpowiedzi:

132

Powodem jest to, że super()działa tylko na klasach w nowym stylu , co w serii 2.x oznacza rozszerzenie z 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
źródło
4
Od jakiej wersji Pythona stało się to domyślnym zachowaniem?
Geo
6
2.2 był, kiedy wprowadzono klasy w nowym stylu, 3.0 jest miejscem, w którym stały się domyślnymi.
Cody Brocious
7
@tsunami, jeśli chcesz dostać się do superklasy, zrób „Xa (siebie)”
James Brady
Myślę, że mnie źle zrozumiałeś. Tryptyk. Pamiętam, że używałem wersji Pythona mniejszej niż 3.0 i nie powiedziałem konkretnie, że moja klasa dziedziczy po Object, a wywołanie super działało. Może to domyślne zachowanie z 2.6? Tylko mówię :)
Geo
Alabaster, naprawdę nie ma takiej potrzeby. Zajęcia w nowym stylu mają wiele zalet, nie tylko super. Nie należy promować sposobów w starym stylu.
Cody Brocious
14

Ponadto nie używaj super (), chyba że musisz. Nie jest to „właściwa rzecz” ogólnego przeznaczenia w przypadku klas w nowym stylu, co można by podejrzewać.

Są chwile, kiedy spodziewasz się wielokrotnego dziedziczenia i możesz tego chcieć, ale dopóki nie poznasz włochatych szczegółów MRO, najlepiej zostaw to w spokoju i trzymaj się:

 X.a(self)
bobince
źródło
2
czy to prawda, ponieważ w ciągu moich 6 miesięcy nauki Python / Django używałem super jako „ogólnie właściwej rzeczy do zrobienia”?
philgo20
1
Cóż, samo w sobie nie zaszkodzi ci to z powodu pojedynczego dziedziczenia (z wyjątkiem tego, że jest trochę wolniejsze), ale też nic ci nie daje. Musisz zaprojektować wszelkie metody, które muszą pomnożyć-dziedziczenie (przede wszystkim __init__), aby przekazywać argumenty w czysty i rozsądny sposób, w przeciwnym razie otrzymasz TypeErrors lub gorsze problemy z debugowaniem, gdy ktoś spróbuje pomnożyć-dziedziczenie przy użyciu Twojej klasy. O ile naprawdę nie zaprojektowałeś obsługi MI w ten sposób (co jest dość trudne), prawdopodobnie lepiej jest uniknąć sugestii super, że metoda jest bezpieczna dla MI.
bobince
3

W przypadku, gdy żadna z powyższych odpowiedzi nie wskazywała tego wyraźnie. Twoja klasa nadrzędna musi dziedziczyć po „obiekcie”, co zasadniczo zmieniłoby ją w nową klasę stylu.

# 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
źródło
Przepraszamy, ale w Pythonie 3.x Twój drugi przykład (dziedziczenie niejawne) tak naprawdę nie działa w kontekście wspomnianego problemu.
sophros
1

Wypróbowałem różne metody Xa (); jednak wydają się one wymagać wystąpienia X w celu wykonania (), więc zrobiłem X (). a (self), co wydaje się bardziej kompletne niż poprzednie odpowiedzi, przynajmniej w przypadku aplikacji, które napotkałem. Wydaje się, że nie jest to dobry sposób na rozwiązanie problemu, ponieważ występuje niepotrzebna budowa i zniszczenie, ale działa dobrze.

Moją aplikacją był moduł cmd.Cmd w Pythonie, który z jakiegoś powodu najwyraźniej nie jest obiektem NewStyle.

Ostateczny wynik:

X().a(self)
weberc2
źródło