सुपर () "टाइपरर: उठता है, टाइप होना चाहिए, न कि क्लासोबज" नई शैली के वर्ग के लिए


335

super()TypeError का निम्न उपयोग : क्यों?

>>> 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 पर एक समान प्रश्न है: Python super () TypeError को उठाता है , जहाँ त्रुटि को इस तथ्य से समझाया जाता है कि उपयोगकर्ता वर्ग एक नई शैली का वर्ग नहीं है। हालाँकि, ऊपर का वर्ग एक नई शैली का वर्ग है, क्योंकि यह इनसे विरासत में मिला है object:

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

मैं क्या खो रहा हूँ? मैं super()यहां कैसे उपयोग कर सकता हूं ?

काम HTMLParser.__init__(self)करने के बजाय का उपयोग करना super(TextParser, self).__init__(), लेकिन मैं TypeError को समझना चाहूंगा।

पुनश्च: जोआचिम ने बताया कि एक नई शैली की श्रेणी का उदाहरण होना एक होने के बराबर नहीं है object। मैंने कई बार विपरीत पढ़ा, इसलिए मेरा भ्रम (उदाहरण के परीक्षण के आधार पर नई शैली के वर्ग उदाहरण परीक्षण का objectउदाहरण: https://stackoverflow.com/revisions/2655651/3 )।


3
आपके प्रश्न और उत्तर के लिए धन्यवाद। मुझे आश्चर्य है कि क्यों 2.7 super.__doc__पुराने बनाम नई शैली के बारे में कुछ भी उल्लेख नहीं करता है!
केल्विन

धन्यवाद। :) दस्तावेज़ में आमतौर पर पूर्ण, HTML संस्करण की तुलना में कम जानकारी होती है। यह तथ्य जो super()केवल नई-शैली की कक्षाओं (और वस्तुओं) के लिए काम करता है, वह HTML doc ( docs.python.org/library/functions.html#super ) में उल्लिखित है
एरिक ओ लेबिगॉट सेप


यह कोई डुप्लिकेट नहीं है (अद्यतन किए गए प्रश्न और स्वीकृत उत्तर देखें)।
एरिक ओ लेबिगॉट

जवाबों:


246

ठीक है, यह सामान्य रूप से " super()पुरानी शैली की कक्षा के साथ उपयोग नहीं किया जा सकता है"।

हालांकि, महत्वपूर्ण बात यह है कि सही परीक्षण के लिए "यह एक नई शैली है उदाहरण (यानी वस्तु)?" है

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

और नहीं (प्रश्न के अनुसार):

>>> isinstance(instance, object)
True

के लिए कक्षाएं , सही परीक्षण है "यह एक नई शैली वर्ग है":

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

महत्वपूर्ण बिंदु है कि पुरानी शैली वर्गों के साथ, है वर्ग एक उदाहरण की और उसके प्रकार अलग हैं। यहाँ, OldStyle().__class__है OldStyle, जिसमें से वारिस नहीं है object, जबकि type(OldStyle())है instanceप्रकार है, जो करता है से विरासत object। मूल रूप से, एक पुरानी शैली का वर्ग केवल प्रकार की वस्तुओं का निर्माण करता है instance(जबकि एक नई शैली की कक्षा उन वस्तुओं का निर्माण करती है, जिनका प्रकार स्वयं कक्षा है)। यह शायद यही कारण है कि उदाहरण है OldStyle()एक है object: अपने type()से विरासत में मिली object(तथ्य यह है कि अपने वर्ग करता नहीं से विरासत objectमें नहीं गिना जाता: पुरानी शैली कक्षाओं केवल प्रकार की नई वस्तुओं का निर्माण instance)। आंशिक संदर्भ:https://stackoverflow.com/a/9699961/42973

पुनश्च: एक नई शैली वर्ग और एक पुरानी शैली के बीच का अंतर भी इसके साथ देखा जा सकता है:

>>> 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

(पुरानी शैली की कक्षाएं प्रकार नहीं हैं, इसलिए वे उनके उदाहरणों के प्रकार नहीं हो सकते हैं)।


11
और इसका एक कारण हमारे पास अब पायथन 3 है
स्टीवन रूंबल्स्की

2
BTW: (Oldstyle().__class__ is Oldstyle)हैTrue
Tino

2
@Tino: वास्तव में, लेकिन यह OldStyle().__class__दिखाने के लिए कि कैसे एक वस्तु ( OldStyle()) एक पुराने-शैली वर्ग से आती है। केवल नई शैली की कक्षाओं को ध्यान में रखते हुए, किसी को isinstance(OldStyle(), object)इसके बजाय परीक्षण करने के लिए लुभाया जा सकता है ।
एरिक ओ लेबिगोट

27
यह अनुमान लगाया गया है कि 2.7.x में अभी भी अजगर मानक पुस्तकालय का कितना हिस्सा है object, जो इस तरह से नहीं मिलता है , इस प्रकार आपको प्रॉक्सी द्वारा खराब कर देता है।
निक बैस्टिन

2
@NickBastin - यह एक संयोग नहीं है। यह सभी को पायथन 3 में धकेलने के लिए है। जहां "सब कुछ पहले से ही ठीक है।" लेकिन - कैवेट एम्प्टर - यह केवल चारा और स्विच है।
टॉमस गैंडर

204

सुपर () का उपयोग केवल नई-शैली की कक्षाओं में किया जा सकता है, जिसका अर्थ है कि मूल वर्ग को 'ऑब्जेक्ट' वर्ग से विरासत में प्राप्त करने की आवश्यकता है।

उदाहरण के लिए, शीर्ष वर्ग को इस तरह होना चाहिए:

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

नहीं

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

तो, समाधान यह है कि इस तरह से सीधे अभिभावक की init विधि को कॉल करें :

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

8
मेरे लिए, मुझे यह करना था: HTMLParser .__ init __ (स्व) मैं उत्सुक हूं कि क्या आपका कोई उदाहरण काम करता है?
चिम्पांजी

1
@ ईओएल क्या मतलब है? jeffp ने बताया कि कॉल selfमें पैरामीटर की कमी के कारण इस उत्तर में दिया गया कोड गलत है HTMLParser.__init__()
पायोत्र डोब्रोगोस्ट

1
@PiotrDobrogost: क्षमा करें, मेरी टिप्पणी LittleQ के उत्तर के बारे में थी, न कि jeffp के (अच्छे) बिंदु के बारे में।
एरिक ओ लेबिगॉट

1
@ जफ़्फ़ सॉरी, यह एक टाइपो है, मैं इसे एसओ पर टाइप करता हूं, लेकिन इसका परीक्षण नहीं किया, मेरी गलती है। सही करने के लिए धन्यवाद
कॉलिन सु

1
एक फिक्स के लिए अपवोट करें जो मौजूदा कोड के साथ काम करता है, जैसे लॉगिंग। python2.6 में सक्रिय करें
डेविड रेनॉल्ड्स

28

आप भी इस्तेमाल कर सकते हैं class TextParser(HTMLParser, object):। यह TextParserएक नई शैली की कक्षा बनाता है , और super()इसका उपयोग किया जा सकता है।


वस्तु से वंशानुक्रम जोड़ना मेरे लिए एक उत्थान है, एक अच्छा विचार है। (यह कहा गया है, यह उत्तर प्रश्न के
टाइप-इयर

23

समस्या यह है कि एक पूर्वज की superजरूरत है 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

करीब से जांच करने पर एक पता चलता है:

>>> type(myclass)
classobj

परंतु:

>>> class newstyle(object): pass

>>> type(newstyle)
type    

तो आपकी समस्या का समाधान ऑब्जेक्ट से और साथ ही HTMLParser से इनहेरिट करना होगा। लेकिन सुनिश्चित करें कि ऑब्जेक्ट MRO में कक्षाओं में आता है:

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

>>> myclass().os
True

मान्य अंक, लेकिन वे पहले से ही पिछले उत्तरों में हैं। इसके अलावा, जांच के बजाय type(myclass), क्या मायने रखता है कि क्या myclassवस्तु से विरासत में मिला है (यानी क्या isinstance(myclass, object)सच है - यह गलत है)।
एरिक ओ लेबिगोट

17

आप विरासत पेड़ (संस्करण 2.6 में) को देखें, तो HTMLParserसे विरासत में मिली SGMLParserहै, जिसमें से विरासत में मिली ParserBaseहै जो नहीं है से विरासत में मिली object। यानी HTMLParser एक पुरानी शैली की क्लास है।

आपकी जाँच के बारे में isinstance, मैंने ipython में एक त्वरित परीक्षण किया:

[1] में: ए श्रेणी:
   ...: उत्तीर्ण करना
   ...: 

[2] में: आइंस्टीनेंस (ए, ऑब्जेक्ट)
बाहर [2]: सच है

यदि कोई वर्ग पुरानी शैली का वर्ग है, तब भी इसका एक उदाहरण है object


2
मेरा मानना ​​है कि सही परीक्षा होनी चाहिए isinstance(A(), object), नहीं isinstance(A, object), नहीं? उत्तरार्द्ध के साथ, आप परीक्षण कर रहे हैं कि क्या वर्ग A एक है object, जबकि सवाल यह है कि क्या उदाहरणों की Aएक कर रहे हैं objectठीक है,?
एरिक ओ लेबिगोट

5
पुनश्च: सबसे अच्छा परीक्षण लगता है issubclass(HTMLParser, object), जो झूठी लौटाता है।
एरिक ओ लेबिगॉट

5

करने का सही तरीका पुरानी शैली की कक्षाओं में निम्नलिखित होगा जो 'ऑब्जेक्ट' से विरासत में नहीं मिलती हैं

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

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

1
प्रश्न में, यह विधि पहले से ही उल्लिखित है: समस्या यह समझने की है कि त्रुटि संदेश क्यों उत्पन्न किया गया था, इसे दूर करने के लिए नहीं (विशेष रूप से इस तरह से)।
एरिक ओ लेबिगॉट

इसके अलावा, यह समाधान उस स्थिति में काम नहीं करेगा कि हम उस कॉल का एक उदाहरण चाहते हैं Aजो किसी राज्य को संग्रहीत करता है।
तशुहका

0

एफडब्ल्यूआईडब्ल्यू और हालांकि मैं कोई अजगर गुरु नहीं हूं जो मुझे इसके साथ मिला

>>> 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
(...)

बस मुझे आवश्यकतानुसार पार्स परिणाम वापस मिल गए।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.