Есть ли способ для функции Python узнать, что она оформляется во время загрузки модуля? - PullRequest
0 голосов
/ 23 октября 2018

в качестве примера:

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

@decorator
def decorated(): pass

есть ли способ у украшенных узнать, что они украшаются?

Ответы [ 2 ]

0 голосов
/ 23 октября 2018

Вы можете использовать декоратор, который использует 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())
0 голосов
/ 23 октября 2018

Ниже приведено частичное решение , которое работает с замыканиями, которые выглядят точно так же, как в вашем примере.

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).Для метода класса вы можете посмотреть Как определить, был ли декоратор применен к методу или функции?

...