函数
在 Python 中,函数 是一等公民 ,函数是对象 ,可以将函数赋予变量
将函数赋值给变量
1 2 3 4 5 6 7 8 9 def func (message ): print ('Got a message: {}' .format (message)) send_message = func print (type (func)) print (type (send_message)) send_message('hello world' )
将函数当成函数参数 传递给另一个函数
1 2 3 4 5 6 7 8 9 10 def get_message (message ): return 'Got a message: ' + message def root_call (func, message ): print (type (func)) print (func(message)) root_call(get_message, 'hello world' )
嵌套函数
1 2 3 4 5 6 7 8 def func (message ): def get_message (msg ): print ('Got a message: {}' .format (msg)) return get_message(message) func('hello world' )
函数可以返回函数对象 - 闭包
1 2 3 4 5 6 7 8 9 10 def func_closure (): def get_message (message ): print ('Got a message: {}' .format (message)) return get_message send_message = func_closure() print (type (send_message)) send_message('hello world' )
函数装饰器
朴素版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 def my_decorator (func ): def wrapper (): print ('wrapper of decorator' ) func() return wrapper def greet (): print ('hello world' ) greet = my_decorator(greet) greet()
优雅版本 - @ 是语法糖 ,相当于 greet=my_decorator(greet)
,提高代码可读性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 def my_decorator (func ): def wrapper (): print ('wrapper of decorator' ) func() return wrapper @my_decorator def greet (): print ('hello world' ) greet()
带有参数 的装饰器
将 *args
和 **kwargs
作为装饰器内部函数 wrapper() 的函数参数
*args
和 **kwargs
- 表示接受任意数量和类型的参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 def my_decorator (func ): def wrapper (*args, **kwargs ): print ('wrapper of decorator' ) func(*args, **kwargs) return wrapper @my_decorator def greet (message ): print (message) @my_decorator def celebrate (name, message ): print (f'{name} is celebrating {message} ' ) greet('hello world' ) celebrate('David' , 'his birthday' )
带有自定义参数 的装饰器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 def repeat (num ): def my_decorator (func ): def wrapper (*args, **kwargs ): for i in range (num): print ('wrapper of decorator' ) func(*args, **kwargs) return wrapper return my_decorator @repeat(4 ) def greet (message ): print (message) greet('hello world' )
greet() 函数被装饰后,函数的元信息 变了
1 2 3 4 5 6 7 print (greet.__name__) help (greet)
使用内置的装饰器 @functools.wraps - 保留 原函数的元信息 - 将原函数的元信息拷贝 到对应的装饰器函数 里面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import functoolsdef my_decorator (func ): @functools.wraps(func ) def wrapper (*args, **kwargs ): print ('wrapper of decorator' ) func(*args, **kwargs) return wrapper @my_decorator def greet (message ): print (message) print (greet.__name__) help (greet)
类装饰器
类装饰器主要依赖于函数 __call__()
,每调用类的实例时,函数 __call__()
都会被执行一次
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Count : def __init__ (self, func ): print (func.__name__) self.func = func self.num_calls = 0 def __call__ (self, *args, **kwargs ): self.num_calls += 1 print ('num of calls is: {}' .format (self.num_calls)) return self.func(*args, **kwargs) @Count def example (): print ("hello world" ) example()
嵌套装饰器 1 2 3 4 5 @decorator1 @decorator2 @decorator3 def func (): ...
执行顺序为从里到外
1 decorator1(decorator2(decorator3(func)))
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 26 27 28 29 30 31 32 import functoolsdef my_decorator1 (func ): @functools.wraps(func ) def wrapper (*args, **kwargs ): print ('execute decorator1' ) func(*args, **kwargs) return wrapper def my_decorator2 (func ): @functools.wraps(func ) def wrapper (*args, **kwargs ): print ('execute decorator2' ) func(*args, **kwargs) return wrapper @my_decorator1 @my_decorator2 def greet (message ): print (message) greet('hello world' )
样例 身份认证 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import functoolsdef authenticate (func ): @functools.wraps(func ) def wrapper (*args, **kwargs ): request = args[0 ] if check_user_logged_in(request): return func(*args, **kwargs) else : raise Exception('Authentication failed' ) return wrapper def check_user_logged_in (request ): pass @authenticate def post_comment (request, **kwargs ): pass
日志记录 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import timeimport functoolsfrom time import sleepdef log_execution_time (func ): @functools.wraps(func ) def wrapper (*args, **kwargs ): start = time.perf_counter() res = func(*args, **kwargs) end = time.perf_counter() print ('{} took {} ms' .format (func.__name__, (end - start) * 1000 )) return res return wrapper @log_execution_time def calculate_similarity (items ): sleep(1 ) calculate_similarity([])
输入检查 1 2 3 4 5 6 7 8 9 10 11 12 import functoolsdef validation_check (func ): @functools.wraps(func ) def wrapper (*args, **kwargs ): ... @validation_check def neural_network_training (param1, param2, **kwargs ): ...
缓存
@lru_cache 会缓存进程中的函数参数 和结果,当缓存满了以后,会删除 least recenly used 数据
1 2 3 4 5 6 from functools import lru_cache@lru_cache def check (param1, param2, **kwargs ) -> bool : ...
小结
类似于 Spring AOP
横切面逻辑 可以基于函数 或者类 (本质也是基于 __call__()
函数,但可以通过类属性 记录更多信息)
装饰器 - 通过装饰器函数 来修改原函数的一些功能 ,而不需要修改原函数代码,相当于一种增强
Decorators is to modify the behavior of the function through a wrapper so we don’t have to actually modify the function.