Интересный вопрос. Вот как бы я поступил.
(Это работает в python2. Я не проверял это в python3, но не удивлюсь, если это не сработает...)
Вы можете перебрать всех «номинантов», используя reversed(inspect.getmro(cls))
, и вернуть первый (выбрав значение next
итератора), который удовлетворяет условию, что он имеет соответствующий attr
, и что attr
совпадает с методом соответствующего cls
.
Сравнение идентичности методов выполняется путем сравнения атрибута im_func
несвязанного метода.
import inspect
def getMethodClass(cls, attr):
return next(
basecls for basecls in reversed(inspect.getmro(cls))
if hasattr(basecls, attr)
and getattr(basecls, attr).im_func is getattr(cls, attr).im_func
)
getMethodClass(A, 'a')
=> __main__.A
getMethodClass(B, 'a')
=> __main__.A
getMethodClass(B, 'b')
=> __main__.B
# an alternative implementation, suggested by @chameleon
def getAttributeClass(cls, attrName):
# check first if has attribute
attr = getattr(cls, attrName)
mro = inspect.getmro(cls)
# only one class on list
if len(mro) == 1:
return cls
# many class on list
for base in reversed(mro[1:]):
# check if defined in this base
try:
baseAttr = getattr(base, attrName)
except AttributeError:
continue
else:
if baseAttr.im_func is attr.im_func:
return base
# define in top class
return cls
Функция также может иметь подпись, которую вы предлагаете:
def getMethodClass(unbound_method):
cls = unbound_method.im_class
attr = unbound_method.__name__
# rest of implementation is the same as before...
getMethodClass(B.a)
=> __main__.A
person
shx2
schedule
06.04.2014
getattr(A, 'a')
— это просто глупый способ написатьA.a
, аtype(A)
— это выражение Python, которое оценивается какtype
— вы, вероятно, хотите простоA
. - person   schedule 06.04.2014