سؤال

كيف يمكنني الحصول على الفصل الذي حدد طريقة في بيثون؟

أريد طباعة المثال التالي "__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)
هل كانت مفيدة؟

المحلول

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

نصائح أخرى

شكرا 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

إرجاع حل الإسكندرية نفس النتائج. طالما يمكن استخدام نهج الإسكندرية، أود استخدامه بدلا من ذلك.

لا أعرف لماذا لم يحضر أحد هذا الأمر أو حول سبب وجود إجابة أعلى 50 عند البطيء عندما تكون بطيئا مثل الجحيم، ولكن يمكنك أيضا القيام بما يلي:

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

بالنسبة لبيتثون 3 أعتقد أن هذا تغير وستحتاج إلى النظر في .__qualname__.

بدأت في القيام بشيء مماثل إلى حد ما، وكانت الفكرة بشكل أساسي تحقق كلما تم تنفيذ طريقة في فئة أساسية أم لا في فئة فرعية. اتضح الطريقة التي لم أتمكن من اكتشافها في الأصل عندما تم تنفيذ فئة وسيطة في الواقع الطريقة.

الحل البديل لأنه كان بسيطا جدا في الواقع؛ وضع طريقة ينسب واختبار وجودها في وقت لاحق. إليك تبسيط الشيء كله:

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() (أليس هذا الروح؟) ولديه يمر جميع الوسائط غير الموحدة للطريقة.

ملاحظة: هذه الإجابة لا يجيب مباشرة على السؤال. IMHO هناك سببان يريد المرء معرفة الفئة المعرفة طريقة؛ أولا هو توجيه الأصابع في فئة في رمز التصحيح (مثل التعامل مع الاستثناء)، والثاني هو تحديد ما إذا كانت الطريقة قد تم إعادة تنفيذها (حيث تعتبر الطريقة عبارة عن كعب كعب يمكن تنفيذها من قبل المبرمج). هذه الإجابة تحل تلك الحالة الثانية بطريقة مختلفة.

في بيثون 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
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top