احصل على فئة طريقة محددة
-
12-09-2019 - |
سؤال
كيف يمكنني الحصول على الفصل الذي حدد طريقة في بيثون؟
أريد طباعة المثال التالي "__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