参考 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"))
|
这里 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"))
|
后面具体解释这些步骤.
创建 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 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")
|
这里的 arg1
和 arg2
形参名是自己定义的, 这里需要注意参数个数的对应.
定义通用的 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()
|