python是否允许我在运行时将动态变量传递给装饰器?

New*_*Guy 3 python decorator python-decorators

我正在尝试在工作中集成一个非常旧的系统和一个更新的系统.我能做的最好的事情就是利用系统使用的RSS消防站类型的饲料.目标是使用此RSS源使其他系统在某些人执行操作时执行某些操作.

我的想法是围绕某些函数包装装饰器,以检查用户(RSS提要中提供的用户ID)是否在新系统中具有权限.

我当前的解决方案有很多看起来像这样的函数,它们基于actionfeed中的字段调用:

actions_dict = {
    ...
    'action1': function1
}

actions_dict[RSSFEED['action_taken']](RSSFEED['user_id'])

def function1(user_id):
    if has_permissions(user_id):
         # Do this function
Run Code Online (Sandbox Code Playgroud)

我想创建一个has_permissions装饰器,user_id以便我可以删除has_permissions每个函数中的冗余检查.

@has_permissions(user_id)
def function1():
    # Do this function
Run Code Online (Sandbox Code Playgroud)

不幸的是,我不知道如何编写这样的装饰器.我看到的所有教程都有一个@has_permissions()带有硬编码值的行,但在我的情况下,它需要在运行时传递,并且每次调用函数时都会有所不同.

我该如何实现此功能?

das*_*s-g 8

在你的问题中,你已经命名了两个,检查了user_id,以及想要的装饰器has_permissions,所以我将使用一个名称更清晰的例子:让我们做一个装饰器,当调用底层(装饰)函数时颜色(一个字符串)是'green'.

Python装饰器是函数工厂

装饰器本身(if_green在我下面的例子中)是一个函数.它需要一个函数作为参数进行修饰(function在我的示例中命名)并返回一个函数(run_function_if_green在示例中).通常,返回的函数在某个时刻调用传递的函数,从而使用它可能在其之前或之后运行的其他操作来"装饰"它,或者两者兼而有之.

当然,它可能只是有条件地运行它,因为你似乎需要:

def if_green(function):
    def run_function_if_green(color, *args, **kwargs):
        if color == 'green':
            return function(*args, **kwargs)
    return run_function_if_green


@if_green
def print_if_green():
    print('what a nice color!')


print_if_green('red')  # nothing happens
print_if_green('green')  # => what a nice color!
Run Code Online (Sandbox Code Playgroud)

当你用装饰器装饰一个函数时(正如我在print_if_green这里所做的那样)会发生装饰器(if_green我的例子中的函数工厂)被原始函数调用(print_if_green正如你在上面的代码中看到的那样).就其本质而言,它返回不同的功能.然后Python 原始函数替换为装饰器返回的函数.

因此,在后续调用中,返回的函数(run_function_if_green原始的print_if_greenas function)被调用,print_if_green并且有条件地调用该原始函数print_if_green.

函数工厂可以生成带参数的函数

对decorator(if_green)的调用仅对每个修饰函数发生一次,而不是每次调用修饰函数时都会发生.但是,当装饰器返回的函数一次性永久替换原始函数时,每次调用原始函数时都会调用它而不是原始函数.如果我们允许的话,它可以采取论据.

我给它一个参数color,它用它来决定是否调用修饰函数.此外,我已经给它了惯用的vararg参数,它用来调用包装函数(如果它调用它),这样我就可以使用任意数量的位置和关键字参数来修饰函数:

@if_green                     
def exclaim_if_green(exclamation):
    print(exclamation, 'that IS a nice color!')

exclaim_if_green('red', 'Yay')  # again, nothing
exclaim_if_green('green', 'Wow')  # => Wow that IS a nice color!
Run Code Online (Sandbox Code Playgroud)

装饰函数的结果if_green是新的第一个参数被添加到其签名之前,该签名对于原始函数是不可见的(因为run_function_if_green它不转发它).由于您可以自由地实现装饰器返回的函数,它还可以使用更少,更多或不同的参数调用原始函数,在将它们传递给原始函数之前对它们执行任何所需的转换,或者执行其他疯狂的操作.

概念,概念,概念

理解装饰器需要了解和理解Python语言的各种其他概念.(其中大多数并非特定于Python,但人们可能仍然不了解它们.)

为了简洁起见(这个答案足够长),我已经跳过或掩盖了大部分内容.有关更全面的快速运行(我认为)所有相关的快速运行,请参阅12个简单步骤中的了解Python装饰器!.

  • 这里的关键是装饰器的一部分使用传递给它的参数(“color”),而不是使用为特定函数定义的值。 (2认同)