我试图用一个可调用类的实例替换它来装饰函数:
class FunctionFaker( object ):
def __init__( self, f ):
self.f= f
def empty_function( self ):
pass
def __call__( self, *args, **kwargs ):
self.f( *args, **kwargs)
def fakefunction( f ):
'''a decorator that transforms a function into a FunctionFaker'''
return FunctionFaker(f)
@fakefunction
def dosomething():
pass
dosomething.empty_function()
dosomething()
这和预期的一样。在
但是,只要我尝试装饰一个类方法:
^{pr2}$我得到一个TypeError: dosomething() takes exactly 1 argument (0 given)
。在
现在,我想I can answer the why:
To support method calls, functions include the
__get__()
method for binding methods during attribute access. This means that all functions are non-data descriptors which return bound or unbound methods depending whether they are invoked from an object or a class.
因此,FunctionFaker不是一个函数,没有所述描述符,因此不会弄乱参数。在
如何实现能够替换实例方法的可调用类?在
这是因为
MethodType
有一个__getattribute__
方法,该方法将未知属性委托给其im_func
:当然,在CPython中,capi并没有完全反映出}之间的Python级别的区别,因此它的真正的实现方式是使用一个定制的^{} 槽。您可以阅读详细信息in the source。在
__getattribute__
和{是的,但只是动态的,通过给你底层可调用的属性。在
我不认为它们是专门打算用类实例来代替具有自己的方法描述符的函数。但即使是将属性附加到方法的简单情况,也需要这种支持。例如,对于一个独立的函数,您可以使用函数属性,例如,记忆缓存,或延迟初始化第一次调用设置。如果
MethodType
没有将属性访问委托给它的im_func
对象,那么将这样一个函数移动到一个类中会破坏它,并且开发人员将无法修复它,除非他知道描述符是如何工作的,并且以一种难看的方式重写了方法。在事实上,在2.3之前,方法甚至没有
__dict__
;正如您从the source看到的那样,除了C槽之外的所有属性都被委托给im_func
(通过有效地复制正常的机制,将所有的东西都委托给im_func
,但会出现包装错误)。关于这个问题有一些争论,你可以通过搜索python dev档案找到christismer在2.4之前的时期发表的一篇文章,文章主题相关(可能是this thread,但我没有读到全部内容…)。从2.4开始,方法现在执行正常的查找机制(除了__doc__
的特殊情况),并且只有在失败时才委托给im_func
。在这有点奇怪,也许将
empty_function
属性添加到function对象中会更简单,而不是将其包装在一个类中……但我认为这并不太合理。(我假设您询问的是您的代码,而不是MethodType
和描述符是如何实现的。)你在正确的轨道上。您希望您的类也是descriptor:
现在,如果您的decorator绑定到一个类,它的行为类似于一个描述符(在decorated函数中将适当的实例绑定到
self
),如果它没有绑定到一个类,它的行为就像一个普通的装饰器。整洁。在相关问题 更多 >
编程相关推荐