Python 将函数状态从方法更改为函数的装饰器

Python 将函数状态从方法更改为函数的装饰器,python,decorator,inspection,Python,Decorator,Inspection,[更新]:回答下面的问题 我有一个检查程序,其中一个目标是让decorator中的逻辑知道它所修饰的函数是类方法还是正则函数。这是以一种奇怪的方式失败的。下面是在Python 2.6中运行的代码: def decorate(f): print 'decorator thinks function is', f return f class Test(object): @decorate def test_call(self): pass if

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

我有一个检查程序,其中一个目标是让decorator中的逻辑知道它所修饰的函数是类方法还是正则函数。这是以一种奇怪的方式失败的。下面是在Python 2.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
然后在执行时:

decorator thinks function is <function test_call at 0x10041cd70>
main thinks function is <bound method Test.test_call of <__main__.Test object at 0x100425a90>>

在函数成为方法之前,将运行装饰程序<类内的code>def关键字在任何其他位置定义函数行,然后类主体中定义的函数作为方法添加到类中。Decorator在类处理函数之前对其进行操作,这就是代码“失败”的原因


@decoration无法看到函数实际上是一个方法。一种解决方法是,不管函数是什么,都要对其进行修饰(例如,添加一个属性
do\u about\u me\u if\u I\u am\u A\u method
-)
),然后在计算完类后再次处理它(迭代类成员,并对修饰后的成员执行任何操作)。

如其他人所说,函数在绑定之前被修饰,因此您无法直接确定它是“方法”还是“函数”

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

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

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

import inspect

def decorate(f):
    def detect(*args, **kwargs):
        try:
            members = inspect.getmembers(args[0])
            members = (x[1].im_func for x in members if 'im_func' in dir(x[1]))
            ismethod = detect in members
        except:
            ismethod = False
        print ismethod

        return f(*args, **kwargs)
    return detect

@decorate
def foo():
    pass

class bar(object):
    @decorate
    def baz(self):
        pass

foo() # prints False
bar().baz() # prints True

不,正如您所要求的,这是不可能的,因为绑定方法和函数之间没有固有的区别。方法只是一个包装好的函数,用于获取调用实例作为第一个参数(使用Python)

像这样的电话:

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

Test.__dict__[ 'test_call' ].__get__( None, spam )
这是一个未绑定的方法,即使

Test.__dict__[ 'test_call' ]
是一个函数。这是因为函数是其
\uuuuu get\uuuu
方法返回方法的描述符;当Python在查找链中看到其中一个时,它会调用
\uuuu get\uuuu
方法,而不是继续向上查找链

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

decorator只是查看定义的函数,而没有在
\uuuu dict\uuuu
中查找它,因此无法判断它是否正在查看绑定方法


也许可以使用修改
\uuu getattribute\uuuu
的类装饰器来实现这一点,但这是一个特别讨厌的黑客行为。为什么您必须具有此功能?当然,由于您必须自己将decorator放置在函数上,因此可以向它传递一个参数,说明所述函数是否在类中定义

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

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

我尝试了一个稍微不同的例子,一个是修饰的方法,一个是未修饰的方法

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

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

if __name__ == '__main__':
  print 'main thinks function is', Test.test_call
  print 'main thinks function 2 is', Test.test_call_2
那么输出是:

decorator thinks function is <function test_call at 0x100426b18>
main thinks function is <unbound method Test.test_call>
main thinks function 2 is <unbound method Test.test_call_2>
decorator认为函数是
主要功能是
主要功能2是

因此,decorator看到的类型与主函数不同,但decorator没有更改函数的类型,否则它将与未修饰的函数不同。

它们实际上作为函数存储在类
\uuuu dict\uuuu
中--试试看!只有当您访问它们时,它们才会被绑定。但是,是的,没有办法,这是可能的。那么,我必须使用getattr()来访问它们。
decorator thinks function is <function test_call at 0x100426b18>
main thinks function is <unbound method Test.test_call>
main thinks function 2 is <unbound method Test.test_call_2>