Python装饰器:如何列出被装饰器包装的函数清单

3

是否可以使用Python装饰器标记一个方法,并在以后使用它,即使我不知道包装函数的名称?

以下是一个例子,我不知道method_with_custom_name方法的名称:

@run_this_method
def method_with_custom_name(my_arg):
    return "The args is: " + my_arg

def _init_and_run():
    # Here, I want to get and call method_with_custom_name
    # but I don't know it's name, 
    # so the next line isn't valid.
    return run_this_method()(my_arg_value)

def run_this_method(m):
    def w(my_arg):
        _do_some_magic(my_arg, m)
    return w

def _do_some_magic(callback_arg, callback):
     if some_checks():
          callback(callback_arg)

那么我该如何获取使用了@run_this_method的方法列表呢?

2个回答

6
如果您需要跟踪所有使用您的装饰器装饰的函数和方法,您需要创建一个全局变量来注册所有这样的函数和方法。我已经修改了您的代码:

如果你需要追踪所有被你的装饰器修饰的函数和方法,你需要创建一个全局变量来注册所有这样的函数和方法。我修改了你的代码:

funcs_registry = [] #List of all functions decorated with @run_this_method
def run_this_method(m):
    global functions_registry
    funcs_registry.append(m) #Add function/method to the registry

    def w(my_arg):
        _do_some_magic(my_arg, m)
    return w

def _do_some_magic(callback_arg, callback):
    if some_checks():
        callback(callback_arg)

@run_this_method
def method_with_custom_name(my_arg):
    return "The args is: " + my_arg

def _init_and_run():
    global functions_registry

    # Here you can iterate over "functions_registry"
    # and do something with each function/method in it
    for m in functions_registry:
        print(m.__name__)

不要使用全局变量functions_registry,可以创建一个类作为装饰器,在实体字段中注册函数。例如:

class FunDecorator:
    def __init__(self):
        self.registry = []

    def __call__(self, m):
        "This method is called when some method is decorated"
        self.registry.append(m) #Add function/method to the registry

        def w(my_arg):
            _do_some_magic(my_arg, m)
        return w

run_this_method = FunDecorator() #Create class instance to be used as decorator

@run_this_method
def method_with_custom_name(my_arg):
    return "The args is: " + my_arg

#do some magic with each decorated method:
for m in run_this_method.registry:
    print(m.__name__)

不,你不需要引入全局状态来做到这一点,就像你在应用程序中跟踪任何东西时从未需要引入全局状态一样。 - Two-Bit Alchemist
@Two-BitAlchemist,能否澄清一下如何在没有全局状态的情况下实现? - Sergiy Kozyr
装饰器是一个对象。只要您拥有该对象的实例,您存储在该对象上的任何内容都可以保留。它不需要全局变量,因为许多成熟的Python项目将显示。 - Two-Bit Alchemist

1
如果我理解你的问题正确(如何装饰一个未知名称的方法?),那么完全有可能。
@decorator
def foo(bar):
  pass

"

"是"syntactic sugar"的简写。

def foo(bar):
  pass
foo = decorator(foo)

所以在你的情况下,你只需要这样做:

method_with_custom_name = run_this_method(method_with_custom_name)

您提供的例子有些令人困惑。为什么您不知道 method_with_custom_name 的名称呢?它就在那里。它被称为 method_with_custom_name。要在以后使用装饰过的版本,只需调用 method_with_custom_name 即可。

因为我正在编写一个库,而其他人将编写具有自定义名称的method_with_custom_nameanother_method_with_custom_name - dkiselev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接