1、纯函数篇
首先有两个概念需要明白,函数对象和内部函数。
函数对象
在python中函数可以当做一个变量使用,因此也可以当做参数传递给其他的函数:
1 2 3 4 5 6 7 |
def invoke_func(func): print(f"function:{func.__name__}") func() def say_hello(): print("hello,quanjie!") invoke_func(say_hello) |
内部函数
1 2 3 4 5 6 7 |
def outer_func(): print("I am outer") def inner_func(): print("I am inner_func") print("invoke inner_func") inner_func() outer_func() |
2、原始装饰器
在这里我将使用原始的方式(函数套用)来实现装饰器的功能。
不带参数的原始装饰器
1 2 3 4 5 6 7 8 9 |
def decorator(func): def wrapper(): func() return wrapper def say_hello(): print("hello") say_ = decorator(say_hello)#-----1 say_()#hello |
没错,这就是一个函数之间的嵌套调用,其中还在decorator中增加了内部函数wrapper,使人感觉多此一举,可以当你看到1处时,你可能就明白了。say_得到的只是一个闭包的环境。
带参数的原始装饰器
1 2 3 4 5 6 7 8 9 10 |
def decorator(func): def wrapper(*args,**kwargs): func(*args,**kwargs) return wrapper def say_hello(people): print(f"hello,{people}") say_ = decorator(say_hello) say_("quanjie")#hello,quanjie |
带参有返回值的原始装饰器
1 2 3 4 5 6 7 8 9 10 11 |
def decorator(func): def wrapper(*args,**kwargs): value = func(*args,**kwargs) return value return wrapper def say_hello(people): return f"hello,{people}" say_ = decorator(say_hello) print(say_("quanjie")) |
可以看到装饰器的作用主要是不修改被装饰的程序而添加新的功能。
3、函数装饰器
原始的装饰器有两点缺点,a、使用过程太过繁琐,b、内部闭包的时候改变了被装饰函数的一下属性等(比如:函数的名称),因此,python中提供一个@的语法糖和functools包。
不带参数的装饰器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
def my_decorator(func): @functools.wraps(func)#******************************* def wrapper(): print("Something is happening before the function is called.") func() print("Something is happening after the function is called.") return wrapper @my_decorator def say_hello(): print("hello") say_hello()#******************************* """ Something is happening before the function is called. hello Something is happening after the function is called. """ |
带参数的装饰器
1 2 3 4 5 6 7 8 9 10 11 12 13 |
""" 带参数的使用方法和原始装饰器的使用方法基本相同 """ def decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): func(*args, **kwargs) return wrapper @decorator def say_hello(people): print(f"hello,{people}") say_hello("quanjie") |
带返回值的装饰器
1 2 3 4 5 6 7 8 9 10 |
def decorator(func): def wrapper(*args,**kwargs): return func(*args,**kwargs) return wrapper @decorator def return_greeting(name): print("Creating greeting") return f'Hi {name}' print(return_greeting("quanjie"))#decorator(return_greeting)("quanjie") #Hi quanjie |
装饰器带有参数的装饰器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
"""调用被装饰的函数4次""" def repeat(num_times): def decorator_repeat(func): @functools.wraps(func) def wrapper_repeat(*args, **kwargs): for _ in range(num_times): value = func(*args, **kwargs) return value return wrapper_repeat return decorator_repeat @repeat(num_times=4) def greet(name): print(f"Hello {name}") return 123 print(greet("quanjie"))#repat(4)(greet)("quanjie") |
看着好像有点别扭,其实把它的执行步骤分开解析就明确了;a、调用repeat函数,返回decorator_repeat,但是这个返回值拥有一个num_times变量的闭包环境,b、运行decorator_repeat同时将函数名greet传给它,返回wrapper_repeat,c、运行wrapper_repeat,重复4次执行greet函数,并将最后一次的返回结果返回给最上层的调用者。
- 我的微信
- 这是我的微信扫一扫
-
- 我的微信公众号
- 我的微信公众号扫一扫
-