Decorator将函数状态从方法更改为函数

2024-09-28 22:20:08 发布

您现在位置:Python中文网/ 问答频道 /正文

[更新]:回答下面的问题

我有一个检查程序,目的是让decorator中的逻辑知道它所修饰的函数是类方法还是正则函数。这以一种奇怪的方式失败了。下面是在Python2.6中运行的代码:

def decorate(f):
    print 'decorator thinks function is', f
    return f

class Test(object):
    @decorate
    def test_call(self):
        pass

if __name__ == '__main__':
    Test().test_call()
    print 'main thinks function is', Test().test_call

执行时:

^{pr2}$

有什么问题的线索吗,以及@decorate是否可以正确地推断test_call是一个方法?在

[答:] 卡尔下面的答案近乎完美。我在子类调用的方法上使用decorator时遇到了一个问题。我修改了他的代码,在超类成员中加入了im\u-func比较:

ismethod = False
for item in inspect.getmro(type(args[0])):
    for x in inspect.getmembers(item):
        if 'im_func' in dir(x[1]):
            ismethod = x[1].im_func == newf
            if ismethod:
                break
    else:
        continue
    break

Tags: 方法函数代码intestifdefdecorator
3条回答

在函数成为方法之前运行decorator。^类中的{}关键字在任何其他地方定义函数行,然后在类的主体中定义的函数作为方法添加到类中。Decorator在函数被类处理之前对其进行操作,这就是您的代码“失败”的原因。在

@decorate无法看到函数实际上是一个方法。一个解决方法是修饰函数,不管它是什么(例如,添加一个属性do_something_about_me_if_I_am_a_method;-)),然后在类被计算之后再次处理它(迭代类成员并对那些修饰的成员做任何你想做的事情)。在

正如其他人所说,函数在绑定之前被修饰过,所以您不能直接确定它是“方法”还是“函数”。在

判断函数是否为方法的合理方法是检查“self”是否是第一个参数。虽然不是万无一失,但大多数Python代码都遵循以下约定:

import inspect
ismethod = inspect.getargspec(method).args[0] == 'self'

这里有一个复杂的方法,似乎可以自动地判断出方法是否是一个边界。适用于cpython2.6上的一些简单案例,但没有承诺。如果函数的第一个参数是绑定了修饰函数的对象,则它决定函数是方法。在

^{pr2}$

不,这是不可能的,因为绑定方法和函数之间没有内在的区别。方法就是一个简单的函数,它将调用实例作为第一个参数(使用Pythondescriptors)。在

像这样的电话:

Test.test_call

它返回一个未绑定的方法,转换为

^{pr2}$

这是一个未绑定的方法,尽管

Test.__dict__[ 'test_call' ]

是一个函数。这是因为函数是其__get__方法返回方法的描述符;当Python在查找链中看到其中一个方法时,它将调用__get__方法,而不是继续向上延伸。在

实际上,函数的“绑定方法”是在运行时确定的,而不是在定义时确定的!在

decorator只看到定义的函数,而不在__dict__中查找它,因此无法判断它是否在查看绑定方法。在


使用修改__getattribute__的类修饰符可以实现这一点,但这是一种特别讨厌的黑客攻击。为什么一定要有这个功能?当然,由于您必须自己将decorator放在函数上,所以您可以向它传递一个参数,说明所述函数是否在类中定义?在

class Test:
    @decorate( method = True )
    def test_call:
        ...

@decorate( method = False )
def test_call:
    ...

相关问题 更多 >