Python-decorator-基础

参考 tutorial

Python decorator 是一个高阶函数, 接受一个函数作为参数, 扩展这个函数后返回 (本质上是返回了一个新函数). 语法示例为:

1
2
3
4
5
6
7
8
9
10
11
def uppercase(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result.upper()
return wrapper

@uppercase
def say_hello(name):
return f"hello, {name}"

print(say_hello("Alice")) # 输出: HELLO, ALICE

这里 uppercase 为定义的 decorator 函数, say_hello 为传入的函数.

@ 是一种特殊的语法 (语法糖), 其等价于:

1
2
3
4
5
6
7
8
9
10
11
def uppercase(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result.upper()
return wrapper

def say_hello(name):
return f"hello, {name}"

say_hello = uppercase(say_hello)
print(say_hello("Alice")) # 输出: HELLO, ALICE

后面具体解释这些步骤.

创建 decorator

Decorator 起作用的本质就是返回一个新函数, 因此需要在函数中定义新函数 (嵌套定义), 由于本意是扩充当前的一个函数, 因此要传入一个函数作为参数, 然后调用, 如:

1
2
3
4
5
6
7
def uppercase_decorator(function):
def wrapper():
func_result = function()
make_uppercase = func_result.upper()
return make_uppercase

return wrapper

对一个函数应用多个 decorator

一个函数可以经多个 decorator 按顺序处理, 如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import functools

def uppercase_decorator(function):
def wrapper():
func = function()
make_uppercase = func.upper()
return make_uppercase

return wrapper

def split_string(function):
@functools.wraps(function)
def wrapper():
func = function()
splitted_string = func.split()
return splitted_string

return wrapper

@split_string
@uppercase_decorator
def say_hi():
return 'hello there'

print(say_hi())

输出为:

1
['HELLO', 'THERE']

需要注意:

1
2
3
4
@split_string
@uppercase_decorator
def say_hi():
return 'hello there'

这里 uppercase_decorator 先运行, 然后再运行 split_string.

在 Decorator 中使用接收函数的参数 (已知参数个数)

如:

1
2
3
4
5
6
7
8
9
10
11
12
def decorator_with_arguments(function):
def wrapper_accepting_arguments(arg1, arg2):
print("My arguments are: {0}, {1}".format(arg1,arg2))
function(arg1, arg2)
return wrapper_accepting_arguments


@decorator_with_arguments
def cities(city_one, city_two):
print("Cities I love are {0} and {1}".format(city_one, city_two))

cities("Nairobi", "Accra")

这里的 arg1arg2 形参名是自己定义的, 这里需要注意参数个数的对应.

定义通用的 decorator (任意数量的参数)

借助 Python 中不定参数的定义语法:

1
2
3
4
def test(*args):
print(args[0])

test("Hello", "World")

则只会输出 Hello. 这里 args 包含了所有的位置参数, 即直接传入值.

若想使用指定形参名的方式, 则需要借助 ** 的语法:

1
2
3
4
def test(*args, **kwargs):
print(args[0], kwargs['haha'])

test("Hello", "World", haha="hahah")

此时的输出则为 Hallo hahah.

应用到 decorator 中如:

1
2
3
4
5
6
7
8
9
10
11
12
def a_decorator_passing_arbitrary_arguments(function_to_decorate):
def a_wrapper_accepting_arbitrary_arguments(*args,**kwargs):
print('The positional arguments are', args)
print('The keyword arguments are', kwargs)
function_to_decorate(*args)
return a_wrapper_accepting_arbitrary_arguments

@a_decorator_passing_arbitrary_arguments
def function_with_no_argument():
print("No arguments here.")

function_with_no_argument()

Python-decorator-基础
http://example.com/2024/04/01/Python-decorator-基础/
作者
Jie
发布于
2024年4月1日
许可协议