此系列文档:python
#它不是黑魔法,只是给包装(wrapper)传递参数: def a_decorator_passing_arguments(function_to_decorate): def a_wrapper_accepting_arguments(arg1, arg2): print("I got args! Look: {0}, {1}".format(arg1, arg2)) function_to_decorate(arg1, arg2) return a_wrapper_accepting_arguments #由于当您调用装饰器返回的函数时,调用的包装器(wrapper),将参数传递给被包装器包装的函数 @a_decorator_passing_arguments def print_full_name(first_name, last_name): print("My name is {0} {1}".format(first_name, last_name)) print_full_name("Peter", "Venkman") # 输出: #I got args! Look: Peter Venkman #My name is Peter Venkman
关于将参数传递给装饰器自己,您怎么认为?code
由于装饰器必须接受一个函数做为参数,因此这可能会有些别扭。orm
所以,您不能将装饰函数的参数直接传递给装饰器。文档
在寻求解决方案以前,让咱们写一些提醒:get
#装饰器是普通函数 def my_decorator(func): print("I am an ordinary function") def wrapper(): print("I am function returned by the decorator") func() return wrapper # 所以,你能够调用它,而不用 "@" def lazy_function(): print("zzzzzzzz") decorated_function = my_decorator(lazy_function) #输出: I am an ordinary function # 它输出了 "I am an ordinary function", 由于你只是调用了装饰器,而没有调用函数: # 这里没有什么神奇的地方,使用'@' @my_decorator def lazy_function(): print("zzzzzzzz") #outputs: I am an ordinary function
结果同样。my_decorator
”被调用了。
所以,当您使用时@my_decorator
,您要告诉Python,经过变量来调用my_decorator
标记了的函数。it
def decorator_maker(): print("I make decorators! I am executed only once: " "when you make me create a decorator.") def my_decorator(func): print("I am a decorator! I am executed only when you decorate a function.") def wrapped(): print("I am the wrapper around the decorated function. " "I am called when you call the decorated function. " "As the wrapper, I return the RESULT of the decorated function.") return func() print("As the decorator, I return the wrapped function.") return wrapped print("As a decorator maker, I return a decorator") return my_decorator #让咱们新建一个装饰器 new_decorator = decorator_maker() #输出: #I make decorators! I am executed only once: when you make me create a decorator. #As a decorator maker, I return a decorator # 让咱们装饰这个函数 def decorated_function(): print("I am the decorated function.") decorated_function = new_decorator(decorated_function) #输出: #I am a decorator! I am executed only when you decorate a function. #As the decorator, I return the wrapped function # 让咱们调用这个函数 decorated_function() #输出: #I am the wrapper around the decorated function. I am called when you call the decorated function. #As the wrapper, I return the RESULT of the decorated function. #I am the decorated function.
绝不奇怪,跟咱们前边演示的内容同样。
让咱们再作一次彻底同样的事情,可是此次咱们跳过全部讨厌的中间变量:
def decorated_function(): print("I am the decorated function.") decorated_function = decorator_maker()(decorated_function) #输出: #I make decorators! I am executed only once: when you make me create a decorator. #As a decorator maker, I return a decorator #I am a decorator! I am executed only when you decorate a function. #As the decorator, I return the wrapped function. # Finally: decorated_function() #输出: #I am the wrapper around the decorated function. I am called when you call the decorated function. #As the wrapper, I return the RESULT of the decorated function. #I am the decorated function.
让咱们把它变的更精简:
@decorator_maker() def decorated_function(): print("I am the decorated function.") #输出: #I make decorators! I am executed only once: when you make me create a decorator. #As a decorator maker, I return a decorator #I am a decorator! I am executed only when you decorate a function. #As the decorator, I return the wrapped function. #最终: decorated_function() #输出: #I am the wrapper around the decorated function. I am called when you call the decorated function. #As the wrapper, I return the RESULT of the decorated function. #I am the decorated function.
嘿,你看到了吗?咱们使用了带有“ @
”语法的函数调用!
所以,回到带有参数的装饰器。
若是咱们可使用函数即时生成装饰器,则能够将参数传递给该函数,对吗?
def decorator_maker_with_arguments(decorator_arg1, decorator_arg2): print("I make decorators! And I accept arguments: {0}, {1}".format(decorator_arg1, decorator_arg2)) def my_decorator(func): #这里传递的参数是闭包的。 #若是您对封包感到不舒服,能够忽略这点。 print("I am the decorator. Somehow you passed me arguments: {0}, {1}".format(decorator_arg1, decorator_arg2)) #不要混淆装饰器参数和函数参数! def wrapped(function_arg1, function_arg2) : print("I am the wrapper around the decorated function.\n" "I can access all the variables\n" "\t- from the decorator: {0} {1}\n" "\t- from the function call: {2} {3}\n" "Then I can pass them to the decorated function" .format(decorator_arg1, decorator_arg2, function_arg1, function_arg2)) return func(function_arg1, function_arg2) return wrapped return my_decorator @decorator_maker_with_arguments("Leonard", "Sheldon") def decorated_function_with_arguments(function_arg1, function_arg2): print("I am the decorated function and only knows about my arguments: {0}" " {1}".format(function_arg1, function_arg2)) decorated_function_with_arguments("Rajesh", "Howard") #输出: #I make decorators! And I accept arguments: Leonard Sheldon #I am the decorator. Somehow you passed me arguments: Leonard Sheldon #I am the wrapper around the decorated function. #I can access all the variables # - from the decorator: Leonard Sheldon # - from the function call: Rajesh Howard #Then I can pass them to the decorated function #I am the decorated function and only knows about my arguments: Rajesh Howard
记住它:带参数的装饰器,能够将变量做为参数:
c1 = "Penny" c2 = "Leslie" @decorator_maker_with_arguments("Leonard", c1) def decorated_function_with_arguments(function_arg1, function_arg2): print("I am the decorated function and only knows about my arguments:" " {0} {1}".format(function_arg1, function_arg2)) decorated_function_with_arguments(c2, "Howard") #输出: #I make decorators! And I accept arguments: Leonard Penny #I am the decorator. Somehow you passed me arguments: Leonard Penny #I am the wrapper around the decorated function. #I can access all the variables # - from the decorator: Leonard Penny # - from the function call: Leslie Howard #Then I can pass them to the decorated function #I am the decorated function and only know about my arguments: Leslie Howard
如您所见,您能够像任何函数传递参数同样传递参数给装饰器。
您甚至能够根据须要使用*args, **kwargs
。
可是请记住,装饰器仅被调用一次,仅在Python导入脚本时。以后,您将没法动态设置参数。
当您执行“ import x”时,该函数已经被修饰,所以您没法进行任何更改。
本文首发于 BigYoung小站