问题描述
[更新]:在问题下面内联
[Updated]: Answer inline below question
我有一个检查程序,一个目的是让装饰器中的逻辑知道它正在装饰的功能是否是一个类方法或常规函数。这以一种奇怪的方式失败了。以下是在Python 2.6中运行的代码:
I have an inspecting program and one objective is for logic in a decorator to know whether the function it is decorating is a class method or regular function. This is failing in a strange way. Below is code run in 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>>
关于出问题的任何线索,以及@decorate是否有可能正确推断出test_call是一种方法?
Any clue on what's going wrong, and if it is possible for @decorate to correctly infer that test_call is a method?
[答案]
卡尔在下面的回答几乎是完美的。在子类调用的方法上使用装饰器时,我遇到了问题。我修改了他的代码,以包括对超类成员的im_func比较:
[Answer]carl's answer below is nearly perfect. I had a problem when using the decorator on a method that subclasses call. I adapted his code to include a im_func comparison on superclass members:
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
推荐答案
就像其他人所说的那样,函数在绑定之前已经被修饰,因此您无法直接确定它是方法还是
As others have said, a function is decorated before it is bound, so you cannot directly determine whether it's a 'method' or 'function'.
一种确定函数是否为方法的合理方法是检查 self是否为第一个参数。虽然不是万无一失,但是大多数Python代码都遵循此约定:
A reasonable way to determine if a function is a method or not is to check whether 'self' is the first parameter. While not foolproof, most Python code adheres to this convention:
import inspect
ismethod = inspect.getargspec(method).args[0] == 'self'
这是一种复杂的方法,似乎可以自动确定该方法是否是绑定方法。在CPython 2.6上仅适用于一些简单的情况,但是没有什么用。
Here's a convoluted way that seems to automatically figure out whether the method is a bound or not. Works for a few simple cases on CPython 2.6, but no promises. It decides a function is a method if the first argument to is an object with the decorated function bound to it.
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
这篇关于装饰器将功能状态从方法更改为功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!