一、闭包
1. 函数的引用
def demo01():
print("---demo01---")
test01 = demo01
test01() # ---demo01---
2. 案例
设计程序计算 y = k * x + b
- 函数
def demo01(x, k=1, b=1):
print(k*x+b)
demo01(0)
demo01(1)
demo01(2)
demo01(0, 2, 2)
demo01(1, 2, 2)
demo01(2, 2, 2)
- 类
class Demo02(object):
def __init__(self, k, b):
self.k = k
self.b = b
def __call__(self, x):
print(self.k * x + self.b)
d1 = Demo02(1, 1)
d1(0)
d1(1)
d1(2)
- 闭包
def outter_func(k, b):
def inner_func(x):
print(k*x+b)
return inner_func
f = outter_func(1, 2)
f(0)
f(1)
f(2)
函数:一般用来实现较简单的项目
闭包:一般用来实现较复杂的项目
类:一般用来实现十分复杂的项目
3. 闭包的概念
-
闭包的构成条件
- 函数的嵌套
- 内部函数使用了外部函数的变量(包括外部函数的参数)
- 外部函数返回内部函数
-
闭包函数的空间中包含了外部函数的变量和内部函数本身
4. 闭包修改外部函数的变量
- 不可变数据类型的外部函数的变量
def outer_func():
n = 0
def inner_func():
nonlocal n # 修改可变类型的对象,需要加上 nonlocal 关键字
n = 1
print(n)
print(f'调用inner_func之前:n={n}')
inner_func()
print(f'调用inner_func之前:n={n}')
return inner_func
f = outer_func()
''' 输出结果
调用inner_func之前:n=0
1
调用inner_func之前:n=1
'''
- 可变数据类型的外部函数的变量
def outer_func():
n = list()
def inner_func():
# nonlocal n # 可变类型可以不加 nonlocal
n.append(1)
print(n)
print(f'调用inner_func之前:n={n}')
inner_func()
print(f'调用inner_func之前:n={n}')
return inner_func
f = outer_func()
''' 输出结果
调用inner_func之前:n=[]
[1]
调用inner_func之前:n=[1]
'''
二、装饰器
1. 装饰器简介
给已有函数增加额外功能的函数,后者的本质是一个闭包函数,在Python中叫做装饰器。
- 装饰器的特点
- 不修改原有函数的代码
- 不改变原有函数的传参
- 不改变原有函数的返回值
- 不改变原有函数的调用方式,即不改变函数的引用名称
写代码要遵循开放封闭原则,它规定已经实现的功能代码不允许被修改,但可以被扩展。
2. 装饰器的使用
# 定义一个装饰器,新增一个功能
def out_func(function): # 这行中out_func是一个装饰器,function只能传入函数的引用
def in_func():
print('新增的功能')
function() # 需要调用被装饰的函数
return in_func
# 创建者写的代码,老代码
# Python中的语法糖,使用装饰器的语法:@装饰器
@out_func # 相当于 func1 = out_func(func1)
def func1():
print('函数func1')
# 调用者,旧的调用方法
# func1()
# 新的调用方法
# 使用func1来保存闭包的目的:因为function已经指向了原函数,func1引用就可以指向新的对象
# func1 = out_func(func1)
func1()
- 随堂练习
# 定义一个计时的装饰器
def count_time(function):
def in_func():
# 函数调用前的时间
t1 = time.time()
function()
# 计算函数调用后的时间差
print(time.time() - t1)
return in_func
@count_time
def func2():
for i in range(100000):
print(i)
@count_time
def func3():
for i in range(10000):
print(i)
######## 下面为调用者的代码,不能修改代码
func2()
func3()
3. 原函数需要传入参数
def out_func(function):
def in_func(a):
print('新增功能')
function(a)
return in_func
@out_func
def func1(x):
print('func1', x)
func1(22)
- 练习
原函数计算两数之和;
定义一个装饰器,给求和结果之前打印一名话:“以下为计算结果:”
def out_func(function):
def in_func(a, b):
print('以下为计算结果:')
function(a, b)
return in_func
@out_func
def sum_(a, b):
rst = a + b
print(rst)
sum_(2, 3)
4. 原函数有return如何处理?
def out_func(function):
def in_func(x, y):
print('以下为计算的结果:')
return function(x, y)
return in_func
@out_func # func1 = out_func(func1)
def func1(x, y):
""" 求和函数 """
rst = x + y
return rst
print(func1(2, 3))
5. 装饰器的通用参数形式
def out_func(function):
def in_func(*args, **kwargs): # 闭包参数的通用形式
print('以下为计算的结果:')
return function(*args, **kwargs) # 返回值的通用形式
return in_func
@out_func # func1 = out_func(func1)
def func1(x=1,y=2):
""" 求和函数 """
rst = x + y
return rst
print(func1(x=2, y=3))
@out_func
def func2():
print('func2')
func2()
6. 多个装饰器
def out_func1(function):
print('开始装饰...1')
def in_func1(*args, **kwargs): # 闭包参数的通用形式
print('01-以下为计算的结果:')
return function(*args, **kwargs) # 返回值的通用形式
return in_func1
def out_func2(function):
print('开始装饰...2')
def in_func2(*args, **kwargs): # 闭包参数的通用形式
print('02-以下为计算的结果:')
return function(*args, **kwargs) # 返回值的通用形式
return in_func2
@out_func2 # func1 = out_func2(func1)
@out_func1 # func1 = out_func1(func1)
def func1(x=1,y=2):
""" 求和函数 """
rst = x + y
return rst
print(func1())
"""
开始装饰...1
开始装饰...2
02-以下为计算的结果:
01-以下为计算的结果:
3
"""
7. 装饰器中传参
- 案例
需求:将原函数执行指定次数?
def dec(n):
def out_func(function):
def in_func(*args, **kwargs):
# 使用for来调用原函数func1
for _ in range(n):
function(*args, **kwargs)
return in_func
return out_func
@dec(3) # dec(3) 返回 out_func
def func1():
print('我中了500万...')
func1()
- 练习
使用一个装饰器在函数的结果之前,打印:
- 这个是两数之和的结果
- 这个是两数之差的结果
def dec(flag):
def out_func(function):
def in_func(*args, **kwargs):
# 判断是求和,还是求差
if flag == '1':
print('这个是两数之和的结果:')
elif flag == '0':
print('这个是两数之差的结果:')
return function(*args, **kwargs)
return in_func
return out_func
@dec('1')
def func1(x, y):
return x + y
print(func1(2, 3))
@dec('0')
def func2(x, y):
return x - y
print(func2(5, 2))
8. 类装饰器
class MyDecrator(object):
# 定义初始化方法,传入函数的引用
def __init__(self, function):
self.__function = function
# 修改定义一个方法来返回一个装饰器
def __call__(self, *args, **kwargs):
print('登录某宝')
return self.__function(*args, **kwargs)
@MyDecrator # 相当于 func1 = MyDecrator(func1)
def func1():
print('在某宝买东西...')
func1()