Source:

Primer on Python Decorators – Real Python

<aside> <img src="/icons/forward_gray.svg" alt="/icons/forward_gray.svg" width="40px" /> Get Your Code: Click here to download the free sample code that shows you how to create and use Python decorators.

</aside>

<aside> <img src="/icons/forward_gray.svg" alt="/icons/forward_gray.svg" width="40px" /> Free Bonus: Click here to get access to a free "The Power of Python Decorators" guide that shows you three advanced decorator patterns and techniques you can use to write cleaner and more Pythonic programs.

</aside>

<aside> <img src="/icons/forward_gray.svg" alt="/icons/forward_gray.svg" width="40px" /> Decorators Cheat Sheet: Click here to get access to a free three-page Python decorators cheat sheet that summarizes the techniques explained in this tutorial.

</aside>

<aside> <img src="/icons/forward_gray.svg" alt="/icons/forward_gray.svg" width="40px" /> Decorators Q&A Transcript: Click here to get access to a 25-page chat log from our Python decorators Q&A session in the Real Python Community Slack where we discussed common decorator questions.

</aside>

Python Functions

为了了解装饰器(Decorators),必须先了解函数工作原理的一些细节。函数有很多方面,但是在装饰器种,一个函数根据给定的参数值返回一个值,以下是一个基本的例子:

>>> def add_one(number):
...     return number + 1
...

>>> add_one(2)
3

总体来说,Python中的函数除了将输入转为输出外还有其他的作用(side effect)。print()函数就是一个例子:它返回None ,同时会向console输出一些信息。但是,将函数想成一个转换参数到输出值的工具已足以了解装饰器(Decorators)

Fist-Class Objects 一级对象

在函数式编程 functional programming中,几乎完全使用没有其他作用(side effect)的纯函数。Python 虽然不是纯函数式语言,但它支持许多函数式编程概念,包括将函数视为一级对象 first-class objects

这意味着**函数(**function)可以作为参数传递和使用,就像任何其他的对象(object)一样,如str,int,float,list等等。

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we're the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")

以上例子中,say_hello()be_awesome() 是常规函数, 需要获取一个string类型的name。而 greet_bob() 函数需要获取一个函数作为参数,例如你可以将say_hello()be_awesome()函数作为输入。

为了测试你的函数,你可以在交互模式(interactive mode)中运行你的代码。这需要使用 -i。例如,如果你的代码在一个名为greeters.py的文件里,那么你应该运行 python -i greeters.py

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we're the awesomest!'

注意 greet_bob(say_hello) 指向两个函数,greet_bob()say_hello() ,但是是以不同的方式。say_hello 函数的命名没有括号,这表示只传递对函数的引用,未执行该函数。greet_bob() 函数写了括号,所以它会被正常调用。