Python闭包&装饰器

闭包 & 装饰器

开放封闭原则

  • 开放:对于添加新功能是开放的
  • 封闭:对于修改原功能是封闭的

闭包

概念

内部函数包含对外部作用域而非全剧作用域变量的引用,则称该内部函数称为闭包函数。

判断方法

输出的__closure__是否有cell元素

作用

  • 为函数增加功能
  • 为函数提前赋值

示例

1
2
3
4
5
def foo():
x = 1
def bar(y):
return x+y
return bar

装饰器(闭包应用)

作用

在不更改原函数调用方式的前提下对原函数添加新功能

原理

利用闭包原理,通过在内部函数中调用外部函数的变量,实现在不改变原函数调用方式的前提下对原函数添加新功能。

种类

  • 简单装饰器
1
2
3
4
5
6
7
8
9
10
11
12
def deco(f):
def wrapper():
"""原函数前添加的功能"""
f()
"""原函数后添加的功能"""
return wrapper

def func():
print('这是原函数!')

func = deco(func)
func()
  • 装饰器的语法糖
1
2
3
4
5
6
7
8
9
10
11
12
def deco(f):
def wrapper():
"""原函数前添加的功能"""
f()
"""原函数后添加的功能"""
return wrapper

@deco # ——>此处效果等同于 func = deco(func)
def func():
print('这是原函数')

func()
  • 带返回值的装饰器
1
2
3
4
5
6
7
8
9
10
11
12
13
def deco(f):
def wrapper():
"""原函数前添加的功能"""
res = f()
"""原函数后添加的功能"""
return res
return wrapper

@deco
def func():
print('这是原函数')

func()
  • 带参数、带返回值的装饰器(标准格式)
1
2
3
4
5
6
7
8
9
10
11
12
13
def deco(f):
def wrapper(*args,**kwargs):
"""原函数前添加的功能"""
res = f(*args,**kwargs)
"""原函数后添加的功能"""
return res
return wrapper

@deco
def func(*args,**kwargs):
print('这是原函数')

func(*args,**kwargs)
  • 多层装饰器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def deco(f):
def outer_wrapper(*args,**kwargs):
def inner_wrapper(*args,**kwargs):
"""原函数前添加的功能"""
res = f(*args,**kwargs)
"""原函数后添加的功能"""
return res
return inner_wrapper
return outer_wrapper

@deco
def func(*args,**kwargs):
print('这是原函数')

func(*args,**kwargs)
  • 多个装饰器修饰同一个函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def deco1(f):
def wrapper(*args,**kwargs):
"""原函数前添加的功能"""
res = f(*args,**kwargs)
"""原函数后添加的功能"""
return res
return wrapper

def deco2(f):
def wrapper(*args,**kwargs):
"""原函数前添加的功能"""
res = f(*args,**kwargs)
"""原函数后添加的功能"""
return res
return wrapper

@deco1 # 其次执行
@deco2 # 首先执行
def func(*args,**kwargs):
print('这是原函数')

func(*args,**kwargs)
  • 装饰器wraps版本(标准格式)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from functools import wraps

def deco(func):
@wraps(func) #加在最内层函数正上方
def wrapper(*args,**kwargs):
return func(*args,**kwargs)
return wrapper

@deco
def origin_func():
'''
这是原函数的注释
:return:
'''
print('这是原函数')

# 虽然已经执行了装饰器,origin_func已经指向wrapper,但是如果用了@wraps(func)装饰器之后调用origin_func的双下划线方法依然是原函数origin_func的
print(origin_func.__name__)
>>> origin_func

print(origin_func.__doc__)
>>> 这是原函数的注释
>>> :return: