[英]Understanding how passing arguments to the decorated function works
I'm learning about Python decorators and I have some difficulties understanding how passing arguments to the decorated function works.我正在学习 Python 装饰器,但我很难理解如何将 arguments 传递给装饰的 function 的工作原理。 I'm not talking about passing arguments to the decorator itself but of the case where the original function takes additional arguments.我不是在谈论将 arguments 传递给装饰器本身,而是原始 function 需要额外的 arguments 的情况。 For instance, I'm trying to understand the following simple example (credits for the code snippet goes to this answer):例如,我试图理解以下简单示例(代码片段的功劳归于这个答案):
def decorator(fn):
def wrapper(arg1, arg2):
print("I got args! Look: {0}, {1}".format(arg1, arg2))
fn(arg1, arg2)
return wrapper
@decorator
def print_full_name(first_name, last_name):
print("My name is {0} {1}".format(first_name, last_name))
print_full_name("John", "Doe")
# outputs:
# I got args! Look: John Doe
# My name is John Doe
So, if I intentionally break the code by removing the arguments arg1
and arg2
of the wrapper, I get the following error: TypeError: wrapper() takes 0 positional arguments but 2 were given
.因此,如果我故意通过删除包装器的 arguments arg1
和arg2
来破坏代码,我会收到以下错误: TypeError: wrapper() takes 0 positional arguments but 2 were given
。 It's strange to me that the wrapper is expecting 2 arguments when it's defined without any arguments inside the parentheses.对我来说很奇怪,当包装器在括号内没有任何 arguments 的情况下定义时,它期望 2 arguments。 Also, is it unclear to me how the first_name
and last_name
argument values are "mapped" to the arguments of the wrapper function.另外,我不清楚first_name
和last_name
参数值是如何“映射”到包装器 function 的 arguments 的。 We only pass those arguments to the print_full_name
function but it seems they also get passed to the wrapper
function.我们只将那些 arguments 传递给print_full_name
function 但似乎它们也传递给了wrapper
function。 Maybe this has to do with the order in which things are run but this is not clear for me.也许这与事情的运行顺序有关,但这对我来说并不清楚。
I know they are a lot of great answers here regarding this topic but I could not find one that clearly explains this specific part.我知道他们在这里有很多关于这个主题的很好的答案,但我找不到一个清楚地解释这个特定部分的答案。 Any help would be greatly appreciated.任何帮助将不胜感激。
In short: passing arguments is exactly the same;简而言之:通过 arguments 是完全一样的; you just need to be aware of which function you are actually calling.您只需要知道您实际调用的是哪个function。
Decorator syntax is just function application in disguise.装饰器语法只是 function 应用程序的变相。 Without it, you would just write没有它,你只会写
def decorator(fn):
def wrapper(arg1, arg2):
print("I got args! Look: {0}, {1}".format(arg1, arg2))
fn(arg1, arg2)
return wrapper
def print_full_name(first_name, last_name):
print("My name is {0} {1}".format(first_name, last_name))
print_full_name = decorator(print_full_name)
So now, print_full_name
does not refer to the original function that prints the sentence.所以现在, print_full_name
并不是指打印句子的原始 function。 It refers to the function returned by decorator
.它指的是装饰器返回的decorator
。 The original function is not lost;原厂function不丢失; the new function is a closure over the name fn
, which is a reference to the original function.新的 function 是名称fn
的闭包,它是对原始 function 的引用。
You should break down the calls that happen.您应该分解发生的呼叫。
So, you have:所以你有了:
def decorator(fn):
def wrapper(arg1, arg2):
print("I got args! Look: {0}, {1}".format(arg1, arg2))
fn(arg1, arg2)
return wrapper
@decorator
def print_full_name(first_name, last_name):
print("My name is {0} {1}".format(first_name, last_name))
print_full_name("John", "Doe")
# outputs:
# I got args! Look: John Doe
# My name is John Doe
Because you have decorated the print_full_name
with the decorator
, then when you do因为你已经用decorator
装饰了print_full_name
,所以当你这样做时
print_full_name("John", "Doe")
first the decorator decorator
is called with argument print_full_name
, as in:首先使用参数print_full_name
调用装饰器装饰decorator
,如下所示:
decorator(print_full_name)("John", "Doe")
The decorator(print_full_name)
is defined as decorator(print_full_name)
定义为
def decorator(fn):
def wrapper(...):
...
...
return wrapper
and returns the wrapper
.并返回wrapper
。 Thus, the above turns out to be:因此,上面的结果是:
wrapper("John", "Doe")
Then, because the wrapper
is defined as然后,因为wrapper
被定义为
def wrapper(arg1, arg2)
in the body of the wrapper
you have that arg1="John"
and arg2="Doe"
.在wrapper
的主体中,您有arg1="John"
和arg2="Doe"
。
Finally, because the wrapper
is defined inside the decorator
, it knows what the fn
is, where fn=print_full_name
.最后,因为wrapper
是在decorator
内部定义的,所以它知道fn
是什么,其中fn=print_full_name
。
And that is how it works.这就是它的工作原理。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.