Поведение, которое вы видите, на самом деле не связано с использованием самого декоратора.Вы также можете сказать следующее:
class C(object):
pass
setattr(C, 'm', lambda a: a) # actually also just: C.m = lambda a: a
print(C.m(1))
И вы все равно получите по существу ту же ошибку.Вы можете прочитать немного больше в документации по Python 2 для пользовательских методов , а именно этих битов:
Обратите внимание, что преобразование из объекта функции в (несвязанный или связанный) методОбъект происходит каждый раз, когда атрибут извлекается из класса или экземпляра.... Также обратите внимание, что это преобразование происходит только для пользовательских функций;другие вызываемые объекты (и все не вызываемые объекты) извлекаются без преобразования.Также важно отметить, что пользовательские функции, которые являются атрибутами экземпляра класса, не преобразуются в связанные методы;это происходит только тогда, когда функция является атрибутом класса.
И исключение, которое вы выполняете, потому что:
Когда вызывается несвязанный объект пользовательского методавызывается базовая функция (im_func) с ограничением на то, что первый аргумент должен быть экземпляром соответствующего класса (im_class) или его производного класса.
Если вы присмотрелесьC.m
, вы увидите:
>>> print(C.m)
<unbound method C.<lambda>>
>>> print(C().m)
<bound method C.<lambda> of <__main__.C object at 0x7f6f6c5fa850>>
Принимая во внимание, что с Python 3 (как было указано в комментарии, эта конструкция прошла бы), поведение будет:
>>> print(C.m)
<function <lambda> at 0x7f69fbe8d0d0>
>>> print(C().m)
<bound method <lambda> of <__main__.C object at 0x7f69fbe89940>>
Примечание C.m
в последнем случае все еще используется как (простая) функция, а не как (несвязанный) метод.
Я не совсем уверен, для чего именно вы в конечном итоге и в каком направлении будете наиболее полезны, но чтобы получить то же поведение, что и в Python 3 для этого кода, вы можете изменить (не то, чтобы я рекомендовал это) C.m()
вызов C.m.__func__()
, чтобы получить прямой доступ к базовой функции.Или с вашим примером:
A.demo_method.__func__(1)