简体   繁体   中英

Pythonic way to assign a decorator to multiple functions?

I need to add a single decorator - my_decorator - to multiple functions. 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.

Is there a clean, Pythonic way to do this? 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.

# 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.

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:

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.

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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