super () yeni tip sınıf için “TypeError: tip olmalı, classobj değil” değerini yükseltir


335

Aşağıdaki kullanım super()bir TypeError oluşturur: neden?

>>> from  HTMLParser import HTMLParser
>>> class TextParser(HTMLParser):
...     def __init__(self):
...         super(TextParser, self).__init__()
...         self.all_data = []
...         
>>> TextParser()
(...)
TypeError: must be type, not classobj

StackOverflow'da da benzer bir soru var: Python super (), TypeError öğesini yükseltir ; burada hata, kullanıcı sınıfının yeni stil sınıfı olmaması gerçeğiyle açıklanır. Bununla birlikte, yukarıdaki sınıf, aşağıdakilerden miras aldığı için yeni bir sınıftır object:

>>> isinstance(HTMLParser(), object)
True

Neyi kaçırıyorum? Burada nasıl kullanabilirim super()?

HTMLParser.__init__(self)Bunun yerine kullanmak super(TextParser, self).__init__()işe yarayacaktır, ancak TypeError'ı anlamak istiyorum.

Not: Joachim, yeni bir tarz sınıf örneği olmanın bir object. Aksini defalarca okudum, bu yüzden karışıklığım (örnek testine dayanan yeni stil sınıfı örnek test objectörneği: https://stackoverflow.com/revisions/2655651/3 ).


3
Sorunuz ve cevabınız için teşekkürler. Acaba 2.7's neden super.__doc__eski vs yeni stil hakkında bir şey söylemiyor!
Kelvin

Teşekkürler. :) Docstrings genellikle belgelerin tam HTML sürümüne göre daha az bilgi içerir. super()Yalnızca yeni stil sınıfları (ve nesneler) için çalıştığı gerçeği HTML belgesinde ( docs.python.org/library/functions.html#super ) belirtilmiştir.
Eric O Lebigot


Bu bir kopya değil (güncellenmiş soruya ve kabul edilen cevaba bakınız).
Eric O Lebigot

Yanıtlar:


246

Tamam, her zamanki " super()eski tarz bir sınıfla kullanılamaz".

Ancak önemli bir nokta olduğunu doğru test için "bu yeni tarzı olduğunu örneği (yani nesne)?" dır-dir

>>> class OldStyle: pass
>>> instance = OldStyle()
>>> issubclass(instance.__class__, object)
False

ve değil (sorudaki gibi):

>>> isinstance(instance, object)
True

İçin sınıflar , doğru bir testtir "Bu yeni tarzı sınıftır":

>>> issubclass(OldStyle, object)  # OldStyle is not a new-style class
False
>>> issubclass(int, object)  # int is a new-style class
True

Önemli nokta , eski tarz sınıfları ile, yani sınıfı , bir örneğin ve türü farklıdır. Burada OldStyle().__class__ise OldStyledevralan etmeyen, objectiken, type(OldStyle())bir instancetür, yok devralan object. Temel olarak, eski stil sınıfı yalnızca tür nesneler yaratır instance(oysa yeni stil sınıfı, sınıfın kendisi olan nesneler oluşturur). Muhtemelen bu yüzdenOldStyle() birobject : type()miras alınır object(sınıfının miras almaması gerçeği objectsayılmaz: eski stil sınıfları sadece yeni tip nesneler oluşturur instance). Kısmi referans:https://stackoverflow.com/a/9699961/42973 .

Not: Yeni stil sınıfı ile eski stil sınıfı arasındaki fark şu şekilde de görülebilir:

>>> type(OldStyle)  # OldStyle creates objects but is not itself a type
classobj
>>> isinstance(OldStyle, type)
False
>>> type(int)  # A new-style class is a type
type

(eski stil sınıfları tür değildir , bu nedenle örneklerinin türü olamazlar).


11
Ve bu şimdi Python 3'e sahip olmamızın nedenlerinden biri.
Steven Rumbalski

2
BTW: (Oldstyle().__class__ is Oldstyle)olduğunuTrue
Tino

2
@Tino: ama asıl mesele, OldStyle().__class__bir nesnenin ( OldStyle()) eski stil sınıfından gelip gelmediğini nasıl test edeceğimizi göstermektir . Sadece yeni stil sınıfları göz önüne alındığında, isinstance(OldStyle(), object)bunun yerine testi yapmaya cazip gelebilir .
Eric O Lebigot

27
2.7.x'te hala python standart kütüphanesinin ne kadarını miras almaması akıl almaz object, böylece sizi proxy ile vidalar .
Nick Bastin

2
@NickBastin - bu bir tesadüf değil. Herkesi Python 3'e itmek için her şey. "Her şey zaten iyi." Ancak - uyarı emptor - sadece yem ve anahtar.
Tomasz Gandor

204

super () yalnızca yeni stil sınıflarında kullanılabilir, yani kök sınıfın 'nesne' sınıfından miras alması gerekir.

Örneğin, en üst sınıf şöyle olmalıdır:

class SomeClass(object):
    def __init__(self):
        ....

değil

class SomeClass():
    def __init__(self):
        ....

Yani çözüm, ebeveynin init yöntemini doğrudan bu şekilde çağırmasıdır :

class TextParser(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
        self.all_data = []

8
Benim için bunu yapmak zorunda kaldım: HTMLParser .__ init __ (self) Son örneğinizin işe yarayıp yaramadığını merak ediyorum?
şempanze

1
@EOL Ne anlama geliyor? jeffp, bu cevapta verilen kodun self, HTMLParser.__init__()çağrıda parametre eksikliği nedeniyle yanlış olduğuna dikkat çekti .
Piotr Dobrogost

1
@PiotrDobrogost: Üzgünüm, konuşmam LittleQ'nun cevabı hakkındaydı, jeffp'in (iyi) noktasıyla ilgili değildi.
Eric O Lebigot

1
@jeffp üzgünüm, bu bir yazım hatası, sadece SO üzerinde yazıyorum ama test etmedim, benim hatam. için teşekkürler
Colin Su

1
Günlüğe kaydetme gibi mevcut kodla çalışan bir düzeltme için oy verin. Python2.6'da biçimlendirme
David Reynolds

28

Ayrıca kullanabilirsiniz class TextParser(HTMLParser, object):. Bu yeniTextParser bir sınıf oluşturur ve kullanılabilir.super()


Nesneden miras eklenmesi iyi bir fikir. (Bu, bu cevabın sorunun TypeError'unu anlama konusuna
değinmediğini söyledi

23

Sorun şu ki bir ata olarak superihtiyaç duyuyor object:

>>> class oldstyle:
...     def __init__(self): self.os = True

>>> class myclass(oldstyle):
...     def __init__(self): super(myclass, self).__init__()

>>> myclass()
TypeError: must be type, not classobj

Daha yakından incelendiğinde:

>>> type(myclass)
classobj

Fakat:

>>> class newstyle(object): pass

>>> type(newstyle)
type    

Bu nedenle, probleminizin çözümü hem nesneden hem de HTMLParser'dan devralmak olacaktır. Ancak nesnenin MRO sınıflarında son geldiğinden emin olun:

>>> class myclass(oldstyle, object):
...     def __init__(self): super(myclass, self).__init__()

>>> myclass().os
True

Geçerli noktalar, ancak zaten önceki cevaplarda. Ayrıca, kontrol etmek yerine, type(myclass)önemli myclassolan nesneden miras alıp almama (yani isinstance(myclass, object)doğru olup olmadığı - yanlıştır).
Eric O Lebigot

17

Eğer, (sürüm 2.6) kalıtım ağacının bakarsak HTMLParserdevralır gelen SGMLParserdevralır hangi değil gelen devralırParserBaseobject . Yani HTMLParser eski tarz bir sınıftır.

Kontrol ile ilgili olarak isinstance, ipython'da hızlı bir test yaptım:

[1] 'de: A sınıfı:
   ...: geçmek
   ...: 

[2]: isinstance (A, object)
Çıkan [2]: True

Bir sınıf eski tarz sınıf olsa bile, hala bir örneğidir object.


2
Doğru testin olması gerektiğine inanıyorum isinstance(A(), object), değil isinstance(A, object)mi? İkincisi ile, ister test ediyoruz sınıf A bir olup objectsoru olup olmadığıdır oysa örnekleri arasında Abir olan object, doğru mu?
Eric O Lebigot

5
Not: En iyi test issubclass(HTMLParser, object)yanlış görünüyor .
Eric O Lebigot

5

'nesne'den miras almayan eski stil sınıflarında doğru yapmanın yolu şöyle olacaktır

class A:
    def foo(self):
        return "Hi there"

class B(A):
    def foo(self, name):
        return A.foo(self) + name

1
Soruda, bu yöntem zaten belirtilmiştir: sorun, bir hata mesajının neden üretildiğini anlamak , onu ortadan kaldırmak değil (özellikle bu şekilde).
Eric O Lebigot

Ayrıca bu çözüm, Abir durumu depolayan sınıfın bir örneğini çağırmak istediğimizde işe yaramayacaktır .
tashuhka

0

FWIW ve ben Python guru olmasam da

>>> class TextParser(HTMLParser):
...    def handle_starttag(self, tag, attrs):
...        if tag == "b":
...            self.all_data.append("bold")
...        else:
...            self.all_data.append("other")
...     
...         
>>> p = TextParser()
>>> p.all_data = []
>>> p.feed(text)
>>> print p.all_data
(...)

Gerektiğinde bana ayrıştırma sonuçlarını geri getirdim.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.