2009-06-07 29 views
52

मैं कक्षा को कैसे प्राप्त कर सकता हूं जो पायथन में एक विधि परिभाषित करता है?कक्षा प्राप्त करें जो परिभाषित विधि

मैं निम्न उदाहरण मुद्रित करने के लिए "__main__.FooClass" चाहते हैं:

class FooClass: 
    def foo_method(self): 
     print "foo" 

class BarClass(FooClass): 
    pass 

bar = BarClass() 
print get_class_that_defined_method(bar.foo_method) 
+0

पाइथन का कौन सा संस्करण आप उपयोग कर रहे हैं? 2.2 से पहले आप im_class का उपयोग कर सकते थे, लेकिन यह बाध्य स्वयं ऑब्जेक्ट के प्रकार को दिखाने के लिए बदला गया था। –

+1

जानना अच्छा है। लेकिन मैं 2.6 का उपयोग कर रहा हूँ। –

उत्तर

54
import inspect 

def get_class_that_defined_method(meth): 
    for cls in inspect.getmro(meth.im_class): 
     if meth.__name__ in cls.__dict__: 
      return cls 
    return None 
+0

यह काम करता है, धन्यवाद! –

+0

आपका स्वागत है! –

+1

धन्यवाद, मुझे अपने – David

5

धन्यवाद Sr2222 उनका कहना है मैं बात याद आ रही थी के लिए ...

यहाँ को सही दृष्टिकोण है जो है एलेक्स की तरह ही, लेकिन कुछ भी आयात करने की आवश्यकता नहीं है। मुझे नहीं लगता कि यह एक सुधार है, हालांकि, विरासत कक्षाओं का एक विशाल पदानुक्रम नहीं है क्योंकि इस दृष्टिकोण को परिभाषित वर्ग के रूप में जल्द ही बंद हो जाता है, पूरे विरासत को getmro के रूप में वापस करने की बजाय। जैसा कि कहा गया है, यह बहुत असंभव परिदृश्य है।

def get_class_that_defined_method(method): 
    method_name = method.__name__ 
    if method.__self__:  
     classes = [method.__self__.__class__] 
    else: 
     #unbound method 
     classes = [method.im_class] 
    while classes: 
     c = classes.pop() 
     if method_name in c.__dict__: 
      return c 
     else: 
      classes = list(c.__bases__) + classes 
    return None 

और उदाहरण:

>>> class A(object): 
...  def test(self): pass 
>>> class B(A): pass 
>>> class C(B): pass 
>>> class D(A): 
...  def test(self): print 1 
>>> class E(D,C): pass 

>>> get_class_that_defined_method(A().test) 
<class '__main__.A'> 
>>> get_class_that_defined_method(A.test) 
<class '__main__.A'> 
>>> get_class_that_defined_method(B.test) 
<class '__main__.A'> 
>>> get_class_that_defined_method(C.test) 
<class '__main__.A'> 
>>> get_class_that_defined_method(D.test) 
<class '__main__.D'> 
>>> get_class_that_defined_method(E().test) 
<class '__main__.D'> 
>>> get_class_that_defined_method(E.test) 
<class '__main__.D'> 
>>> E().test() 
1 

एलेक्स समाधान देता है एक ही परिणाम। जब तक एलेक्स दृष्टिकोण का उपयोग किया जा सकता है, मैं इसके बजाय इसका उपयोग करूंगा।

+0

'Cls()। Meth .__ self__' आपको 'क्ल्स' का उदाहरण देता है जो 'मेथ' के उस विशिष्ट उदाहरण से जुड़ा हुआ है। यह 'Cls()। Meth.im_class' के समान है। यदि आपके पास 'वर्ग एससीएलएस (सीएलएस)' है, तो 'एससीएलएस()। Meth .__ self__' आपको' एसएलएलएस 'उदाहरण मिलेगा, न कि' क्ल्स 'उदाहरण। ओपी चाहता है कि 'सीएलएस' प्राप्त करना है, जो दिखाई देता है केवल एमआरओ को @ एलेक्स मार्टेलि के रूप में चलकर उपलब्ध है। –

+0

@ sr2222 आप सही हैं। मैंने जवाब को संशोधित कर दिया है क्योंकि मैंने पहले ही शुरू कर दिया है हालांकि मुझे लगता है कि एलेक्स समाधान अधिक कॉम्पैक्ट है। – estani

+0

यदि आपको आयात से बचने की आवश्यकता है तो यह एक अच्छा समाधान है, लेकिन चूंकि आप मूल रूप से एमआरओ को फिर से कार्यान्वित कर रहे हैं, इसलिए यह हमेशा के लिए काम करने की गारंटी नहीं देता है। एमआरओ शायद वही रहेगा, लेकिन यह पहले से ही पाइथन के अतीत में बदल चुका था, और यदि यह फिर से बदला जाता है, तो यह कोड सूक्ष्म, व्यापक बग होगा। –

1

मैंने कुछ हद तक समान कुछ करना शुरू कर दिया, मूल रूप से यह विचार तब भी जांच रहा था जब बेस क्लास में कोई विधि लागू की गई थी या उप-वर्ग में नहीं। जिस तरह से मैंने मूल रूप से ऐसा किया था, उसे बदल दिया, जब मैं मध्यवर्ती वर्ग वास्तव में विधि को कार्यान्वित कर रहा था तो मुझे पता नहीं लगा सका।

इसके लिए मेरा कामकाज वास्तव में काफी सरल था; एक विधि विशेषता विशेषता और बाद में इसकी उपस्थिति का परीक्षण।

class A(): 
    def method(self): 
     pass 
    method._orig = None # This attribute will be gone once the method is implemented 

    def run_method(self, *args, **kwargs): 
     if hasattr(self.method, '_orig'): 
      raise Exception('method not implemented') 
     self.method(*args, **kwargs) 

class B(A): 
    pass 

class C(B): 
    def method(self): 
     pass 

class D(C): 
    pass 

B().run_method() # ==> Raises Exception: method not implemented 
C().run_method() # OK 
D().run_method() # OK 

अद्यतन:: यहाँ पूरी बात का एक सरलीकरण है असल में run_method() से method() फोन (नहीं है कि भावना?) है और यह सभी तर्क विधि के लिए असंशोधित पारित किया है।

पीएस .: यह उत्तर सीधे प्रश्न का उत्तर नहीं देता है। आईएमएचओ दो कारण हैं जो एक जानना चाहते हैं कि किस वर्ग ने एक विधि परिभाषित की है; सबसे पहले डिबग कोड (जैसे अपवाद हैंडलिंग में) में एक कक्षा में उंगलियों को इंगित करना है, और दूसरा यह निर्धारित करना है कि विधि को फिर से कार्यान्वित किया गया है (जहां विधि प्रोग्रामर द्वारा लागू की जाने वाली स्टब है)। यह जवाब दूसरे मामले को एक अलग तरीके से हल करता है।

2

मैं नहीं जानता कि क्यों कोई भी कभी भी इस लाया गया है या जब यह नरक के रूप में धीमी गति से कारण है कि शीर्ष जवाब 50 upvotes है, लेकिन आप भी कर सकते हैं निम्नलिखित:

def get_class_that_defined_method(meth): 
    return meth.im_class.__name__ 

अजगर 3 के लिए मेरा मानना ​​है कि यह बदल गया है और आपको .__qualname__ में देखना होगा।

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