2010-04-24 9 views
6

super(B, self).method() को एक साधारण अच्छे bubble() कॉल में कनवर्ट करने का प्रयास कर रहा है। क्या यह, see below था!सुपर() पाइथन 2.x में बिना तर्क के

क्या इस उदाहरण में कक्षा बी का संदर्भ प्राप्त करना संभव है?

class A(object): pass 

class B(A): 
    def test(self): 
     test2() 

class C(B): pass 

import inspect 
def test2(): 
    frame = inspect.currentframe().f_back 
    cls = frame.[?something here?] 
    # cls here should == B (class) 

c = C() 
c.test() 

असल में, CB का बच्चा है, BA का बच्चा है। फिर हम c प्रकार C बनाते हैं। फिर c.test() पर कॉल वास्तव में B.test() (विरासत के माध्यम से) को कॉल करता है, जो test2() पर कॉल करता है।

test2() पैरेंट फ्रेम frame प्राप्त कर सकते हैं; frame.f_code के माध्यम से विधि के लिए कोड संदर्भ; selfframe.f_locals['self'] के माध्यम से; लेकिन type(frame.f_locals['self'])C (बेशक) है, लेकिन B नहीं है, जहां विधि परिभाषित की गई है।

B पाने के लिए कोई भी तरीका?

+0

यदि मैं पूछ सकता हूं ... आपको इसके लिए क्या चाहिए? क्योंकि मैं शायद ही सोचता हूं कि ऐसा कुछ भी किसी भी चीज़ के लिए सबसे अच्छा तरीका हो सकता है। – Wolph

+0

मैं वास्तव में कुछ प्रकार के सरल 'बबल()' कॉल वाले उपयोगकर्ताओं के लिए 'सुपर (बी, स्वयं) .test() 'को सरल बनाने की कोशिश कर रहा हूं। असल में, मुझे पहले से ही एक रास्ता मिल गया है। –

+0

क्या आप 'सुपर (स्वयं .__ class__, self) .test() 'नहीं कर सका? – Wolph

उत्तर

3

नीचे से super(B, self).test() ->bubble() करने का एक छोटा रास्ता मिला।

(एकाधिक वंशानुक्रम के साथ काम करता, तर्क की आवश्यकता नहीं है, correcly उप-वर्गों के साथ बर्ताव करता है)

समाधान inspect.getmro(type(back_self)) (जहां back_self कॉल प्राप्त करने वाला से एक self है) का इस्तेमाल किया गया है, तो cls के रूप में यह पुनरावृत्ति method_name in cls.__dict__ साथ और यह सत्यापित करना कि हमारे पास कोड संदर्भ इस वर्ग में है (find_class_by_code_object(self) नेस्टेड फ़ंक्शन में महसूस किया गया है)।

bubble() आसानी से *args, **kwargs के साथ बढ़ाया जा सकता है।

import inspect 
def bubble(*args, **kwargs): 
    def find_class_by_code_object(back_self, method_name, code): 
     for cls in inspect.getmro(type(back_self)): 
      if method_name in cls.__dict__: 
       method_fun = getattr(cls, method_name) 
       if method_fun.im_func.func_code is code: 
        return cls 

    frame = inspect.currentframe().f_back 
    back_self = frame.f_locals['self'] 
    method_name = frame.f_code.co_name 

    for _ in xrange(5): 
     code = frame.f_code 
     cls = find_class_by_code_object(back_self, method_name, code) 
     if cls: 
      super_ = super(cls, back_self) 
      return getattr(super_, method_name)(*args, **kwargs) 
     try: 
      frame = frame.f_back 
     except: 
      return 



class A(object): 
    def test(self): 
     print "A.test()" 

class B(A): 
    def test(self): 
     # instead of "super(B, self).test()" we can do 
     bubble() 

class C(B): 
    pass 

c = C() 
c.test() # works! 

b = B() 
b.test() # works! 

यदि किसी के पास कोई बेहतर विचार है, तो इसे सुनें।

ज्ञात बग: (धन्यवाद डबलपी) यदि C.test = B.test -> "अनंत" रिकर्सन। यद्यपि यह वास्तव में एक विधि के लिए बाल वर्ग के लिए यथार्थवादी लगता है, यह = 'माता-पिता से एक एड है।

ज्ञात bug2: (धन्यवाद doublep) सजाया तरीकों से काम नहीं करेगा (शायद unfixable, के बाद से डेकोरेटर को बंद करने देता है) ... for _ in xrange(5) साथ फिक्स्ड डेकोरेटर समस्याओं: ... frame = frame.f_back - 5 संभाल लेंगे सजावट, यदि आवश्यक हो तो वृद्धि। मुझे पायथन पसंद है!

प्रदर्शन super() कॉल से 5 गुना अधिक खराब है, लेकिन हम प्रति सेकंड एक लाख कॉल बनाम 200K कॉल के बारे में बात कर रहे हैं, अगर यह आपके सबसे अच्छे लूप में नहीं है - चिंता करने का कोई कारण नहीं है।

+0

मुझे यकीन नहीं है कि यह सजाए गए कार्यों के लिए काम करेगा। साथ ही, मुझे आशा है कि प्रदर्शन 'bubble()' के लिए आपके उपयोगकेस में सीई महत्वपूर्ण नहीं है। – doublep

+0

एक और (वास्तविक उपयोग में काफी संभावना नहीं) बग: अगर सबक्लास 'def foo ...', तो 'bar = foo' करता है तो' bar() 'में' बबल() 'को छोड़कर काम नहीं किया जाएगा क्योंकि 'method_name' गलत तरीके से "foo" का मूल्यांकन किया जाएगा। – doublep

+1

बार = foo: अगर मैं 'B.test_alias = B.test' और फिर' c.test_alias() 'करता हूं, तो यह अपेक्षित के रूप में' A.test() 'को कॉल करता है। निष्पादन ठीक है, 5000 एनएस (नैनोसेकंड) बबल() बनाम 900ns सुपर (...) के लिए। यह एक बूंद है, लेकिन मैं इसे एक विशाल के रूप में नहीं देखता हूं। –

-1

चूंकि पाइथन में कार्य कक्षाओं [1] से बंधे नहीं हैं, सामान्य उत्तर "संभव नहीं है"। हालांकि, गैर स्थिर कार्यों कि विशेषताओं के लिए मानक नामकरण परंपरा का पालन करने के लिए आप शायद

inspect.currentframe() .f_back.f_locals [ 'स्वयं'] की कोशिश कर सकते। वर्ग

[1] उदाहरण के लिए, तुम कर सकते हो:

class X: pass 
X.foo = (lambda self: None) 

संपादित करें:

मैं एक तरह से पहले से ही विचाराधीन वर्तमान का सुझाव करने में कामयाब रहे: - /। हालांकि, मैं अभी भी उत्सुक हूं कि आप ऐसा करने में कैसे कामयाब रहे, क्योंकि मैं अभी भी कुछ फ़ंक्शन पाइथन में कक्षाओं से बंधे नहीं हैं।

+0

के लिए काम करता है वास्तव में, मैं इसे एक सेकंड में प्रकाशित करूंगा। (स्थैतिक तरीकों के लिए जरूरी नहीं है, क्योंकि मैं सुपर() के प्रतिस्थापन की तलाश कर रहा था, जो केवल बाध्य तरीकों पर चलता है) –

+0

@doublep: 1. 'X.foo.im_class' का मूल्यांकन करने का प्रयास करें और आप आश्चर्यचकित होंगे। 2. आपके द्वारा प्रस्तावित समाधान प्रश्न में प्रकट होता है। – interjay

+1

@interjay: ओह अरे, वास्तव में। अंत में पढ़ने के लिए मुझे यही मिलता है :(हालांकि, 'X.foo.im_class' इस मामले में मदद नहीं करेगा।' वाई.फू = एक्स.फू 'आज़माएं; फ़ंक्शन वही होगा, लेकिन ' im_class' नहीं: यह विधि बाध्यकारी वस्तु की एक संपत्ति है, फ़ंक्शन नहीं। – doublep

0

हालांकि इस कोड को किसी भी सामान्य उद्देश्य के लिए कभी भी उपयोग नहीं किया जाना चाहिए। प्रश्न का उत्तर देने के लिए, यहां कुछ काम कर रहा है;)

import inspect 

def test2(): 
    funcname = inspect.stack()[1][3] 
    frame = inspect.currentframe().f_back 
    self = frame.f_locals['self'] 

    return contains(self.__class__, funcname) 

def contains(class_, funcname): 
    if funcname in class_.__dict__: 
     return class_ 

    for class_ in class_.__bases__: 
     class_ = contains(class_, funcname) 
     if class_: 
      return class_ 
+0

ठीक है, यह मूल रूप से मैंने नीचे किया है, हालांकि आपको नहीं लगता कि inspect.getmro() का उपयोग करना __bases__ से बेहतर है? इसके अलावा आप यह भी परीक्षण नहीं करते कि फ़ंक्शन वास्तव में वह है जिसे इसे कहा जाता है, वर्ग 'सी' में 'test' फ़ंक्शन भी हो सकता है। मेरा जवाब उस पर ख्याल रखता है। –

+0

दरअसल, मुझे बस एमआरओ विधि नहीं मिली, इसलिए मैंने इसे स्वयं अनुकरण किया। आपकी विधि निश्चित रूप से बेहतर है। हालांकि मैं अभी भी तर्क देता हूं कि दोनों गलत समाधान हैं। – Wolph

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