简体   繁体   English

将装饰器分配给多个功能的Pythonic方法?

[英]Pythonic way to assign a decorator to multiple functions?

I need to add a single decorator - my_decorator - to multiple functions. 我需要将单个装饰器my_decorator添加到多个功能。 Instead of adding @my_decorator above each function definition, I'd like to add it to all the functions in an isolated code block, so I have everything in one place. 与其在每个函数定义上方添加@my_decorator ,我不希望将其添加到一个隔离代码块中的所有函数中,因此我将所有内容都放在一个位置。

Is there a clean, Pythonic way to do this? 有没有一种干净的Pythonic方式来做到这一点? Obviously I can do the following, but it gets a bit repetitive. 显然,我可以执行以下操作,但是它有些重复。 If I ever change the decorator name, I'll need to update it in every single line. 如果更改装饰器名称,则需要在每一行中对其进行更新。

function1 = my_decorator(function1)
function2 = my_decorator(function2)
function3 = my_decorator(function3)

My second thought was to put the functions in a list and iterate through it, but neither of the below approaches worked. 我的第二个想法是将函数放在列表中并对其进行迭代,但是以下两种方法均无效。 They modify the value at each list index, while leaving the original functions unchanged, so I would have to call, for example, function_list[0]() to get the function which has the decorator added. 它们修改每个列表索引处的值,同时保持原始功能不变,因此我将不得不调用例如function_list[0]()来获得添加了装饰器的功能。

# approach one - a list comprehension
function_list = [function1, function2, function3]
function_list = [my_decorator(function) for function in function_list]

# approach two - a for loop
function_list = [function1, function2, function3]
for index in range(len(function_list)):
    function_list[index] = my_decorator(function_list[index])

I finally found an approach that works, but using exec() doesn't seem very Pythonic, so I'm wondering if there's a better way. 我终于找到了一种可行的方法,但是使用exec()似乎不太像Python,所以我想知道是否有更好的方法。

function_list = ['function1', 'function2', 'function3']
for index in range(len(function_list)):
    exec("{0} = my_decorator({0})".format(function_list[index]))

Here is the code I was testing this out on, which would add a decorator that prints "Hello" before the function is called: 这是我正在对此进行测试的代码,它将在调用该函数之前添加一个装饰器,该装饰器打印“ Hello”:

def my_decorator(function):
    def wrapper(*args, **kwargs):
        print("Hello!", end=' ')
        return function(*args, **kwargs)
    return wrapper

def ask_about_day(name):
    print("How is your day going, {0}?".format(name))

def comment_about_weather():
    print("It's lovely outside today, isn't it?")

# assign decorator using exec() - possibly unpythonic
function_list = ['ask_about_day', 'comment_about_weather']

for index in range(len(function_list)):
    exec("{0} = my_decorator({0})".format(function_list[index]))

def main():
    name = input("What is your name? ").capitalize()
    if name:
        ask_about_day(name)
    else:
        comment_about_weather()


main()

This is almost certainly a really bad idea. 这几乎肯定是一个非常糟糕的主意。

What you're trying to do is replace arbitrary globals, by name. 您要尝试的是用名称替换任意全局变量。 The right way to do that is to call globals and modify the resulting dict. 正确的方法是调用globals并修改结果字典。

For example: 例如:

g = globals()
for func in function1, function2, function3:
    g[func.__name__] = my_decorator(func)

Of course this looks ugly and hacky, but that's because what you're doing is inherently ugly and hacky, so Python isn't going to go out of its way to make it look nice so you can pretend otherwise. 当然,这看起来很丑陋,但是那是因为您所做的天生就是丑陋而又黑土,所以Python不会竭尽全力使其看起来不错,因此您可以假装其他方式。

Also, notice that however you do this, you're forced to repeat the names of all of your functions at least once. 另外,请注意, 无论执行此操作,您都必须至少重复一次所有函数的名称。 Is that really worth it to avoid repeating the name of your decorator the same number of times? 避免重复装饰器名称相同次数真的值得吗? It's at least as much typing, and a lot easier to get silently wrong. 至少和打字一样多,并且更容易出错。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM