python函数是否有办法知道在模块加载时正在修饰它?

时间:2018-10-23 05:11:31

标签: python python-decorators

例如:

def decorator(func): 
    def nested(*args, **kwargs):
        return func(*args, **kwargs)
    return nested

@decorator
def decorated(): pass

有没有办法让装饰者知道它正在被装饰?

2 个答案:

答案 0 :(得分:1)

以下是一个部分解决方案,适用于与您的示例完全相似的闭包。

import inspect

def decorator(func):
    def nested(*args, **kwargs):
        return func(*args, **kwargs)

    return nested

@decorator
def decorated(): pass

def not_decorated(): pass

print(inspect.getclosurevars(decorated).nonlocals)
print(inspect.getclosurevars(not_decorated).nonlocals)

# => {'func': <function decorated at 0x10e1408c8>}
# => {}

像您这样的装饰函数将具有闭包变量,尽管不能保证其他函数不会。

此外,inspect中还有其他可以玩的东西。另外,如果首先使用functools.wrap(@kindall),将很容易。对于类方法,您可以查询How to detect is decorator has been applied to method or function?

答案 1 :(得分:1)

您可以使用装饰器,该装饰器使用ast.NodeVistor遍历函数的AST节点以查找函数的装饰器。如果装饰器列表包含的内容不止装饰器检查器本身,则可以从装饰器节点获取其他装饰器的详细信息:

import inspect
import ast
from textwrap import dedent

class CheckDecorators(ast.NodeVisitor):
    def visit_FunctionDef(self, node):
        if len(node.decorator_list) > 1:
            print("function '%s' is decorated by: %s" % (node.name, ', '.join(ast.dump(decorator) for decorator in node.decorator_list if not isinstance(decorator, ast.Name) or decorator.id != 'check_decorators')))

def check_decorators(func):
    CheckDecorators().visit(ast.parse(dedent(inspect.getsource(func))))
    return func

这样:

def decorator(func):
    def nested(*args, **kwargs):
        return func(*args, **kwargs)
    return nested

@decorator
@check_decorators
def decorated():
    pass

将输出:

function 'decorated' is decorated by: Name(id='decorator', ctx=Load())