gon*_*opp 6 python class decorator
我试图通过将其替换为可调用类的实例来修饰函数:
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()
Run Code Online (Sandbox Code Playgroud)
这按预期工作.
但是,只要我尝试装饰一个类方法:
class Test( object ):
@fakefunction
def dosomething(self):
pass
t=Test()
t.dosomething.empty_function()
t.dosomething()
Run Code Online (Sandbox Code Playgroud)
我得到了TypeError: dosomething() takes exactly 1 argument (0 given).
现在,我想我可以回答原因:
为了支持方法调用,函数包括
__get__()在属性访问期间绑定方法的方法.这意味着所有函数都是非数据描述符,它们返回绑定或未绑定方法,具体取决于它们是从对象还是类调用.
因此,不是函数的FunctionFaker没有所述描述符,因此不会破坏参数.
如何实现能够替换实例方法的可调用类?
\n\n\n我刚刚意识到我可以简单地实现
\n__get__并返回 atypes.MethodType,但我不太明白这样做如何仍然使您能够调用empty_function。
这是因为MethodType有一个__getattribute__方法将未知属性委托给它im_func:
>>> t.dosomething\n<bound method Test.? of <__main__.Test object at 0x107639550>>\n>>> \'empty_function\' in dir(t.dosomething)\nFalse\n>>> t.dosomething.__getattribute__\n<method-wrapper \'__getattribute__\' of instancemethod object at 0x109583aa0>\n>>> t.dosomething.__getattribute__(\'empty_function\')\n<bound method FunctionFaker.empty_function of <__main__.FunctionFaker object at 0x1095f2510>>\nRun Code Online (Sandbox Code Playgroud)\n\n当然,在 CPython 中,C API 并不完全反映 和 之间的 Python 级别区别__getattribute__,__getattr__因此它的真正实现方式是使用自定义getattro槽。您可以阅读源代码中的详细信息。
\n\n\n它只是成为实例的属性吗
\nMethodType?
是的,但只能动态地通过为您提供底层可调用的属性。
\n\n我不认为他们专门打算让类实例用自己的方法描述符替换函数。但是,即使是将属性附加到方法的简单情况也需要这种支持。例如,对于独立函数,您可以将函数属性用于记忆缓存或首次调用时延迟初始化设置等。如果MethodType没有委托对其im_func对象的属性访问,将这样的函数移动到类中会破坏它,并且开发人员将无法修复它,除非他知道描述符如何工作并以丑陋的方式重写该方法。
事实上,在 2.3 之前,方法甚至没有__dict__; 正如您从源代码中看到的那样,除了 C 插槽之外的所有im_func属性都被委托给(通过有效地复制正常机制来将所有内容委托给im_func除了包装错误之外)。关于这一点存在一些争论,您可能可以通过在 python-dev 档案中搜索 Christian Tismer 在 2.4 之前的时期发表的一篇具有相关主题的帖子来找到这些争论(可能是这个线程,但我没有阅读全文\xe2\x80\xa6)。从 2.4 开始,方法现在执行正常的查找机制(除了 的特殊情况__doc__),并且仅委托给im_func在失败时才委托给。
\n\n\n这是明智之举吗?
\n
这有点奇怪,将属性添加到函数对象中可能empty_function会更简单,而不是将其包装在类\xe2\x80\xa6 中,但我不认为这太不合理。(我假设你问的是你的代码,而不是如何MethodType实现和描述符的实现。)