एक वर्ग विधि के साथ सुपर का उपयोग करना


83

मैं पायथन में सुपर () फ़ंक्शन सीखने की कोशिश कर रहा हूं।

मैंने सोचा कि जब तक मैं इस उदाहरण (2.6) पर नहीं आया, तब तक मैं खुद को समझ पाया।

http://www.cafepy.com/article/python_attributes_and_methods/python_attributes_and_methods.html#super-with-classmethod-example

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "test.py", line 9, in do_something
    do_something = classmethod(do_something)
TypeError: unbound method do_something() must be called with B instance as first argument (got nothing instead)
>>>

जब मैंने इस पंक्ति को उदाहरण से ठीक पहले पढ़ा था, तो यह अपेक्षित नहीं था:

यदि हम क्लास विधि का उपयोग कर रहे हैं, तो हमारे पास सुपर को कॉल करने के लिए कोई उदाहरण नहीं है। सौभाग्य से हमारे लिए, सुपर एक तर्क के रूप में भी काम करता है। --- नीचे दिखाए गए अनुसार टाइप को सीधे सुपर में पास किया जा सकता है।

जो वास्तव में पायथन मुझे बताता है, यह कहकर संभव नहीं है कि do_something () को B के उदाहरण के साथ बुलाया जाना चाहिए।


जवाबों:


99

कभी-कभी ग्रंथों को विवरण के बजाय विचार के स्वाद के लिए अधिक पढ़ना पड़ता है। यह उन मामलों में से एक है।

में लिंक किए गए पृष्ठ , उदाहरण 2.5, 2.6 और 2.7 चाहिए सब एक प्रयोग विधि, do_your_stuff। (अर्थात, do_somethingको बदल दिया जाना चाहिएdo_your_stuff ।)

इसके अलावा, जैसा कि नेड डीली ने बताया , A.do_your_stuffएक वर्ग विधि है।

class A(object):
    @classmethod
    def do_your_stuff(cls):
        print 'This is A'

class B(A):
    @classmethod
    def do_your_stuff(cls):
        super(B, cls).do_your_stuff()

B.do_your_stuff()

super(B, cls).do_your_stuff एक बाध्य विधि देता है ( फुटनोट 2 देखें )। चूंकि clsदूसरा तर्क के रूप में पारित किया गया था super(), इसलिए यह है clsकि लौटे विधि के लिए बाध्य हो जाता है। दूसरे शब्दों में, clsविधि के पहले तर्क के रूप में पारित हो जाता हैdo_your_stuff() कक्षा ए के ।

दोहराना करने के लिए: super(B, cls).do_your_stuff()कारणों Aकी do_your_stuffविधि के साथ कहा जा clsपहला तर्क के रूप में पारित कर दिया। है कि काम करने के लिए, के लिए आदेश में Aकी do_your_stuff एक वर्ग विधि हो गया है। लिंक किए गए पृष्ठ में ऐसा उल्लेख नहीं है, लेकिन यह निश्चित रूप से मामला है।

पुनश्च। do_something = classmethod(do_something)एक classmethod बनाने का पुराना तरीका है। नया (एर) तरीका @classmethod डेकोरेटर का उपयोग करना है।


ध्यान दें कि super(B, cls)इसे प्रतिस्थापित नहीं किया जा सकता है super(cls, cls)। ऐसा करने से अनंत लूप बन सकते हैं। उदाहरण के लिए,

class A(object):
    @classmethod
    def do_your_stuff(cls):
        print('This is A')

class B(A):
    @classmethod
    def do_your_stuff(cls):
        print('This is B')
        # super(B, cls).do_your_stuff()  # CORRECT
        super(cls, cls).do_your_stuff()  # WRONG

class C(B):
    @classmethod
    def do_your_stuff(cls):
        print('This is C')
        # super(C, cls).do_your_stuff()  # CORRECT
        super(cls, cls).do_your_stuff()  # WRONG

C.do_your_stuff()

उठेंगे RuntimeError: maximum recursion depth exceeded while calling a Python object

यदि clsहै C, तो उसके बाद आने वाले वर्ग को super(cls, cls)खोजता है ।C.mro()C

In [161]: C.mro()
Out[161]: [__main__.C, __main__.B, __main__.A, object]

चूंकि वह वर्ग है B, जब clsहै C, super(cls, cls).do_your_stuff() हमेशा कॉल करता है B.do_your_stuff। चूंकि super(cls, cls).do_your_stuff()अंदर कहा जाता है B.do_your_stuff, आप कॉल करना समाप्त करते हैंB.do_your_stuff एक अनंत लूप में ।

Python3 में, 0-तर्क के रूपsuper को जोड़ा गया था, इसलिए super(B, cls)इसे प्रतिस्थापित किया जा सकता है super(), और Python3 इस संदर्भ में पता लगाएगा कि किसकी super()परिभाषा के class Bबराबर होना चाहिए super(B, cls)

लेकिन किसी भी परिस्थिति में super(cls, cls)(या समान कारणों से super(type(self), self)) कभी भी सही नहीं होता है।


सुपर (cls, cls) का उपयोग करने में क्या नुकसान हैं?
जॉर्ज मौट्सपूलोस

2
@GeorgeMoutsopoulos: super(cls, cls)लगभग निश्चित रूप से एक गलती है। मैंने ऊपर पोस्ट संपादित की है कि क्यों समझा।
अनटुब

39

पायथन 3 में, आप के लिए तर्क निर्दिष्ट करना छोड़ सकते हैं super,

class A:
    @classmethod
    def f(cls):
        return "A's f was called."

class B(A):
    @classmethod
    def f(cls):
        return super().f()

assert B.f() == "A's f was called."

यदि यह विशेष प्रश्न अजगर 2 के साथ विशेष रूप से व्यवहार कर रहा है, तो यह उत्तर दूसरे प्रश्न में ले जाया जा सकता है (यह लिंक्ड वेबसाइट के बाद से बताना मुश्किल है, कैफ़ेपी अब उपलब्ध नहीं है)।
टैंकबोट

यह मेरे लिए एक परियोजना में काम नहीं कर रहा है। यह दे रहा हैRuntimeError: super(): no arguments
1919

4

मैंने इसे थोड़ा स्पष्ट करने के लिए लेख को अपडेट किया है: पायथन एट्रीब्यूट्स एंड मेथड्स # सुपर

ऊपर दिए गए classmethod का उपयोग करने वाले आपके उदाहरण से पता चलता है कि एक वर्ग विधि क्या है - यह पहले पैरामीटर के रूप में उदाहरण के बजाय कक्षा को ही पास करता है। लेकिन आपको विधि को कॉल करने के लिए किसी उदाहरण की भी आवश्यकता नहीं है, उदाहरण के लिए:

>>> class A(object):
...     @classmethod
...     def foo(cls):
...         print cls
... 
>>> A.foo() # note this is called directly on the class
<class '__main__.A'>

2

वेब पेज से उदाहरण प्रकाशित के रूप में काम करने लगता है। क्या आपने do_somethingसुपरक्लास के लिए एक विधि बनाई, लेकिन इसे एक वर्गमंथ में नहीं बनाया? कुछ इस तरह से आपको वह त्रुटि मिलेगी:

>>> class A(object):
...     def do_something(cls):
...         print cls
... #   do_something = classmethod(do_something)
... 
>>> class B(A):
...     def do_something(cls):
...         super(B, cls).do_something()
...     do_something = classmethod(do_something)
... 
>>> B().do_something()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in do_something
TypeError: unbound method do_something() must be called with B instance as first argument (got nothing instead)

नहीं, मेरा A वर्ग इस तरह दिखता है: class A (ऑब्जेक्ट): def do_your_stuff (सेल्फ): प्रिंट "यह एक है" क्या यह आवश्यक है कि "क्लास ए" आपके पास पोस्ट करते समय है? (do_something = classmethod (do_something) के साथ)? मुझे लगता है कि दस्तावेज़ ने इस बारे में कुछ भी नहीं बताया ..
dza

1
superबी do_something विधि में कॉल का पूरा बिंदु अपने एक सुपरक्लेसेस में उस नाम की एक विधि को कॉल करना है। यदि A (या ऑब्जेक्ट में) में कोई नहीं है, तो B ()। Do_something () कॉल विफल रहता है super object has no attribute do_something। ~ अनटुब सही बताता है कि दस्तावेज़ में उदाहरण दोषपूर्ण है।
नेड डिली

0

मुझे लगता है कि मैं इस खूबसूरत साइट और प्यारे समुदाय की बदौलत इस बिंदु को समझ गया हूं।

यदि आप बुरा नहीं मानते हैं तो कृपया मुझे सही करें यदि मैं वर्गमिथोड पर गलत हूं (जो अब मैं पूरी तरह से समझने की कोशिश कर रहा हूं):


# EXAMPLE #1
>>> class A(object):
...     def foo(cls):
...             print cls
...     foo = classmethod(foo)
... 
>>> a = A()
>>> a.foo()
# THIS IS THE CLASS ITSELF (__class__)
class '__main__.A'

# EXAMPLE #2
# SAME AS ABOVE (With new @decorator)
>>> class A(object):
...     @classmethod
...     def foo(cls):
...             print cls
... 
>>> a = A()
>>> a.foo()
class '__main__.A'

# EXAMPLE #3
>>> class B(object):
...     def foo(self):
...             print self
... 
>>> b = B()
>>> b.foo()
# THIS IS THE INSTANCE WITH ADDRESS (self)
__main__.B object at 0xb747a8ec
>>>

मुझे उम्मीद है कि यह दृष्टांत दिखाता है।


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