是否有可能检查一个函数/方法以确定它是否可以用作装饰器?是否按照通常的方式包装其他函数并返回一个可调用对象?具体而言,我要验证第三方代码。
是否有可能检查一个函数/方法以确定它是否可以用作装饰器?是否按照通常的方式包装其他函数并返回一个可调用对象?具体而言,我要验证第三方代码。
由于Python没有标准化的装饰器,所以除非你知道要查找的装饰器的相关信息,否则没有真正的方法可以判断一个函数是否是装饰器。
如果装饰器在您的控制范围内,您可以添加一个标记来指示它是一个已装饰的函数。否则,没有真正统一的方法来实现这一点。例如:
def decorator(func):
return g
@decorator
def f()
pass
def g():
pass
__call__
方法,您可以猜测给定的可调用对象是否是装饰器。但这只是一个猜测,而不是保证。classmethod
和staticmethod
装饰器返回描述符对象,而不是函数。
- 自语言版本2.6以来,您可以装饰类,而不仅仅是函数和方法。
- 包含一个 __init__(self,somecallable)
方法和一个 __call__(self,* args,** kwargs)
方法的任何类都可以用作装饰器。@foo
def bar(...):
“exactly”与“完全相同”意思相同。
def bar(...):
...
bar = foo(bar)
自然而然地,由于foo
可能返回任何东西,你无法检查函数是否已被装饰。虽然foo
可以很好地留下标记,但它没有这样做的义务。
如果您有一些 Python 代码,并且想找出所有的装饰器,可以将代码解析为抽象语法树,然后遍历该树以查找已装饰的函数。以下是一个示例,存储装饰器的.id
。显然,如果需要,您也可以存储ast
对象。
>>> class DecoratorFinder(ast.NodeVisitor):
... def __init__(self, *args, **kwargs):
... super(DecoratorFinder, self).__init__(*args, **kwargs)
... self.decorators = set()
...
... def visit_FunctionDef(self, node):
... self.decorators.update(dec.id for dec in node.decorator_list)
... self.generic_visit(node)
...
>>> finder = DecoratorFinder()
>>> x = ast.parse("""
... @dec
... def foo():
... pass
... """)
>>> finder.visit(x)
>>> finder.decorators
set(['dec'])
不,这是不可能的。也许你应该思考一下为什么需要检查f
是否是装饰器,而不是检查它是否是装饰器。
如果你期望某些特定的装饰器,你可以直接检查它们;如果你想要某些特定的行为/方法/属性,你可以检查它们。
如果你想要检查某个可调用的f
是否可以用作装饰器,你可以通过传递一些虚拟函数来测试装饰器的行为,但通常情况下它可能无法正常工作或对不同的输入具有不同的行为。
以下是一个这样的简单检查:
def decorator1(func):
def _wrapper(*args, **kwargs):
print "before"
func(*args, **kwargs)
print "after"
return _wrapper
def dummy_func(): pass
out_func = decorator1(dummy_func)
if callable(out_func) and dummy_func != out_func:
print "aha decorated!"
我从未做过这样的事情,但通常情况下,Python 在这种情况下依赖于“鸭子类型”。因此,您可以尝试装饰一个虚拟函数并查看是否返回可调用对象。