简体   繁体   English

了解如何将 arguments 传递给经过修饰的 function 的工作原理

[英]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 arg1arg2来破坏代码,我会收到以下错误: 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_namelast_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.

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