【问题标题】:Is there a way for a python function to know it is getting decorated at module load time?有没有办法让 python 函数知道它在模块加载时被修饰?
【发布时间】:2018-10-23 05:11:31
【问题描述】:

举个例子:

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

@decorator
def decorated(): pass

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

【问题讨论】:

  • 为什么函数需要知道它正在被修饰?你想达到什么目的?
  • 它可以检测到一些包装器(特别是使用functools.wraps() 的函数式包装器,它们通过添加到包装函数的指示属性,尤其是在 Python 3 中)。但是装饰器不需要添加包装器,如果有,包装器不需要是函数,如果是,它可能不会使用functools.wraps()
  • 简而言之,我遇到了一个问题,我查看了函数参数列表。当我遇到一个有效的函数时,可以说,装饰所述函数可能会导致问题。我应该澄清这是我正在开发的一个我担心的库的用例。
  • 那你为什么不在装饰器中添加错误检查呢?为什么函数必须知道它正在被修饰?
  • 因为我没有开发装饰器。已经解释了为什么它需要知道被装饰,参考上面的评论。

标签: python python-decorators


【解决方案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())

【讨论】:

  • 我相信这就是我想要的。谢谢
【解决方案2】:

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

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?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-05
    • 2020-01-15
    • 2021-11-14
    • 2017-12-06
    • 2023-03-15
    相关资源
    最近更新 更多