2013-10-26 8 views
125

अजगर 3.x में, super() तर्क के बिना कहा जा सकता है:पायथन 3.x का सुपर() जादू क्यों है?

class A(object): 
    def x(self): 
     print("Hey now") 

class B(A): 
    def x(self): 
     super().x() 
>>> B().x() 
Hey now 

आदेश में इस काम करने के लिए, कुछ संकलन समय जादू किया जाता है, एक परिणाम जिनमें से है कि निम्नलिखित कोड (जो supersuper_ को rebinds) में विफल रहता है:

super_ = super 

class A(object): 
    def x(self): 
     print("No flipping") 

class B(A): 
    def x(self): 
     super_().x() 
>>> B().x() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 3, in x 
RuntimeError: super(): __class__ cell not found 

क्यों super() रेस करने में असमर्थ है कंपाइलर से सहायता के बिना रनटाइम पर superclass olve? क्या ऐसी व्यावहारिक स्थितियां हैं जिनमें इस व्यवहार, या इसके लिए अंतर्निहित कारण, एक अनचाहे प्रोग्रामर काट सकता है?

... और, एक साइड प्रश्न के रूप में: क्या फ़िथन, विधियों आदि के पाइथन में कोई अन्य उदाहरण हैं जिन्हें उन्हें एक अलग नाम पर पुनर्निर्मित करके टूटा जा सकता है?

+6

मैं आर्मिन दूँगा पर यह [एक] समझा (कर http://lucumr.pocoo.org/2010/1/7/पेशेवरों और विपक्ष के बारे में-अजगर -3 /)। यह भी एक और अच्छा [पोस्ट] है (http://lucumr.pocoo.org/2013/5/21/porting-to-python-3-redux/) –

+0

संबंधित: http://stackoverflow.com/q/36993577/674039 – wim

उत्तर

184

डीआरआरवाई का उल्लंघन करने से बचने के लिए नया जादू super() व्यवहार जोड़ा गया था। (स्वयं को दोहराएं) सिद्धांत, PEP 3135 देखें।

class Foo(Bar): 
    def baz(self): 
     return super(Foo, self).baz() + 42 

Spam = Foo 
Foo = something_else() 

Spam().baz() # liable to blow up 

ही, वर्ग सज्जाकार जहां डेकोरेटर एक नया ऑब्जेक्ट का उपयोग कर जो rebinds पर लागू होता है: स्पष्ट रूप से एक वैश्विक रूप में यह हवाला वर्ग के नाम पर होने पर भी एक ही rebinding मुद्दों आप super() के साथ ही पता चला की संभावना है वर्ग के नाम:

@class_decorator_returning_new_class 
class Foo(Bar): 
    def baz(self): 
     # Now `Foo` is a *different class* 
     return super(Foo, self).baz() + 42 

जादू super()__class__ सेल आप मूल वर्ग वस्तु का उपयोग करने देने के द्वारा अच्छी तरह से इन मुद्दों को नजरअंदाज कर देता है।

पीईपी को गिडो द्वारा लात मार दिया गया था, जो initially envisioned super becoming a keyword, और वर्तमान कक्षा was also his को देखने के लिए सेल का उपयोग करने का विचार था। निश्चित रूप से, इसे एक कीवर्ड बनाने का विचार first draft of the PEP का हिस्सा था।

हालांकि, वास्तव में यह वास्तव में Guido खुद था जो stepped away from the keyword idea as 'too magical', इसके बजाय वर्तमान कार्यान्वयन का प्रस्ताव है। उन्होंने anticipated that using a different name for super() could be a problem:

मेरे पैच एक मध्यवर्ती समाधान का उपयोग करता है: यह आप __class__ जरूरत है जब भी आप 'super' नामक एक चर का उपयोग बढ़ जाता है। इस प्रकार, यदि आप (विश्व स्तर पर) supersupper को नाम बदलने और प्रयोग supper नहीं बल्कि super, यह तर्क के बिना काम नहीं करेगा (लेकिन यह अभी भी अगर आप इसे पारित काम करेंगे या तो __class__ या वास्तविक वर्ग वस्तु); यदि आपके पास वैरिएबल नाम super है, तो चीजें काम करेंगी लेकिन विधि सेल चर के लिए उपयोग किए जाने वाले थोड़ा धीमे कॉल पथ का उपयोग करेगी।

तो, अंत में, यह गुइडो खुद कि घोषणा की है कि एक super कीवर्ड का उपयोग सही महसूस नहीं किया था, और कहा कि एक जादू __class__ सेल उपलब्ध कराने के एक स्वीकार्य समझौता था।

मैं मानता हूं कि कार्यान्वयन का जादू, निहित व्यवहार कुछ हद तक आश्चर्यजनक है, लेकिन super() भाषा में सबसे गलत तरीके से लागू कार्यों में से एक है। बस इंटरनेट पर पाए गए सभी misapplied super(type(self), self) या super(self.__class__, self) आमंत्रणों पर एक नज़र डालें; यदि उस कोड में से कोई भी कभी व्युत्पन्न वर्ग you'd end up with an infinite recursion exception से बुलाया गया था। बहुत कम सरलीकृत super() कॉल, तर्क के बिना, से बचाता है कि समस्या।

नाम बदलकर super_; आपकी विधि के साथ-साथ में __class__ संदर्भित करें और यह फिर से काम करेगा। अगर आप अपने विधि में संदर्भ या तो superया__class__ नाम सेल बनाई गई है:

>>> super_ = super 
>>> class A(object): 
...  def x(self): 
...   print("No flipping") 
... 
>>> class B(A): 
...  def x(self): 
...   __class__ # just referencing it is enough 
...   super_().x() 
... 
>>> B().x() 
No flipping 
+1

अच्छा लेखन-अप। हालांकि यह अभी भी मिट्टी के रूप में स्पष्ट है। आप कह रहे हैं कि सुपर() स्वचालित रूप से तत्काल तत्काल फ़ंक्शन के बराबर है जैसे 'def super (of_class = magic __class __) 'जैसे' self.super(); डीफ सुपर (स्वयं): खुद को वापस करें .__ class__'? –

+12

@ चार्ल्स मेरियम: यह पोस्ट इस बारे में नहीं है कि तर्क के बिना 'सुपर()' कैसे काम करता है; यह ज्यादातर * क्यों * मौजूद है के साथ सौदा करता है। 'क्लास विधि' में 'सुपर() ', सुपर (संदर्भ ToClassMethodIsBeingDefinedIn, self)' के समतुल्य है, जहां' ReferenceToClassMethodIsBeingDefinedIn' संकलन समय पर निर्धारित किया गया है, विधि को '__class__' नामक बंद करने के रूप में विधि से जोड़ा गया है, और' सुपर() रनटाइम पर कॉलिंग फ्रेम से दोनों देखेंगे। लेकिन आपको वास्तव में यह सब जानने की ज़रूरत नहीं है। –

+1

@ चार्ल्स मेरियम: लेकिन 'सुपर() 'स्वचालित रूप से तत्काल तत्काल फ़ंक्शन * के नजदीक नहीं है, नहीं। –

संबंधित मुद्दे