कक्षा को परिभाषित पद्धति से प्राप्त करें


89

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

मैं निम्नलिखित उदाहरण चाहता हूं कि " __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)

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

1
जानकार अच्छा लगा। लेकिन मैं 2.6 का उपयोग कर रहा हूं।
जेसी एल्ड्रिज

जवाबों:


70
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

1
धन्यवाद, मुझे यह पता लगाने
डेविड

खबरदार, सभी वर्ग लागू नहीं __dict__! कभी-कभी __slots__उपयोग किया जाता है। getattrयदि कक्षा में विधि है, तो परीक्षण करने के लिए उपयोग करना बेहतर है ।
कोडी कोडमोंकी

16
के लिए Python 3, कृपया इस जवाब
योएल

27
मैं मिल रहा हूँ:'function' object has no attribute 'im_class'
Zitrax

5
पायथन 2.7 में यह काम नहीं करता है। लापता 'im_class' के बारे में समान त्रुटि।
RedX

8

धन्यवाद 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

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


Cls().meth.__self__बस आपको उस का उदाहरण देता Clsहै जो उस विशिष्ट उदाहरण से जुड़ा हुआ है meth। इसके अनुरूप है Cls().meth.im_class। यदि आपके पास है class SCls(Cls), तो SCls().meth.__self__आपको एक SClsउदाहरण मिलेगा , उदाहरण नहीं Cls। ओपी चाहता है कि वह प्राप्त करे Cls, जो यह प्रतीत होता है कि केवल एमआरओ चलने से ही उपलब्ध है जैसा @Alex Martelli करता है।
सिलास रे

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

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

समय और समय फिर से, "बहुत संभावना नहीं परिदृश्य" प्रोग्रामिंग में होते हैं। शायद ही कभी, आपदाओं के कारण। सामान्य तौर पर, कोडिंग करते समय सोच पैटर्न "XY.Z% यह कभी नहीं होगा" बेहद घटिया सोच वाला उपकरण है। इसका उपयोग न करें। 100% सही कोड लिखें।
ulidtko

@ulidtko मुझे लगता है कि आप स्पष्टीकरण को गलत बताते हैं। यह शुद्धता नहीं बल्कि गति के बारे में है। कोई भी "संपूर्ण" समाधान नहीं है जो सभी मामलों में फिट बैठता है, अन्यथा उदाहरण के लिए केवल एक छँटाई एल्गोरिथ्म होगा। यहां प्रस्तावित समाधान "दुर्लभ" मामले में तेज होना चाहिए। चूंकि गति पठनीयता के बाद सभी मामलों के 99% प्रतिशत में आती है, इसलिए यह समाधान "केवल" उस दुर्लभ मामले में बेहतर समाधान हो सकता है। यदि आपने इसे नहीं पढ़ा है, तो कोड, 100% सही है, यदि आपने ऐसा किया है तो आपको डर है।
एस्टनी

6

मुझे नहीं पता कि कोई भी इसे कभी क्यों नहीं लाया है या क्यों शीर्ष उत्तर में 50 अपवोट हैं जब यह नरक के रूप में धीमा है, लेकिन आप निम्न कार्य भी कर सकते हैं:

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

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


2
हम्म। जब मैं अजगर 2.7 में ऐसा करता हूं तो मुझे परिभाषित करने वाली कक्षा दिखाई नहीं दे रही है - मुझे वह वर्ग मिल रहा है जिस पर विधि को बुलाया गया था, न कि जहां इसे परिभाषित किया गया है ...
F1Rumors

5

पायथन 3 में, यदि आपको वास्तविक वर्ग वस्तु की आवश्यकता है तो आप कर सकते हैं:

import sys
f = Foo.my_function
vars(sys.modules[f.__module__])[f.__qualname__.split('.')[0]]  # Gets Foo object

यदि फ़ंक्शन एक नेस्टेड वर्ग से संबंधित हो सकता है, तो आपको निम्नानुसार पुनरावृत्त करने की आवश्यकता होगी:

f = Foo.Bar.my_function
vals = vars(sys.modules[f.__module__])
for attr in f.__qualname__.split('.')[:-1]:
    vals = vals[attr]
# vals is now the class Foo.Bar

2

अजगर ३

इसे बहुत ही सरल तरीके से हल किया:

str(bar.foo_method).split(" ", 3)[-2]

यह देता है

'FooClass.foo_method'

वर्ग और फ़ंक्शन नाम को अलग-अलग प्राप्त करने के लिए डॉट पर विभाजित करें


वाह क्या बचा!
user3712978

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

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

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

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