闭包函数和装饰器
一、闭包函数
1.什么是闭包函数?
字面意思:闭:封闭,包:包裹;闭包函数就是函数嵌套,函数对象,名称空间与作用域的结合体
-
闭包函数必须在函数内部定义
-
闭包函数可以引用外层函数的名字
2.闭包函数怎么用
闭包函数是为了装饰器做准备
def outer(num2): num2 = 100 def inner(): # inner就是闭包函数 print(num2) # 如果局部找不到变量名,再从全局找 return inner # 返回innerfunc = outer("num2") # 本质是将inner函数名(函数地址)赋值给funcfunc() # 调用inner函数
举例:# 直接传值import requests# 调用爬虫包def spider_func(url): response = requests.get(url) # 接受网址的返回值 if response.status_code == 200: # 判断http的状态码是不是200 print(len(response.text)) # print(response.text)url = 'https://www.taobao.com/'spider_func(url)# 通过闭包函数传值import requestsdef spider_outer(url): def spider_inner(): response = requests.get(url) print(len(response.text)) return spider_inner url = 'https://www.taobao.com/'spider_func = spider_outer(url) # 本质是spider_inner这个函数的函数地址spider_func()
二、装饰器
1.什么是装饰器?
字面意思就是修饰的工具,就是一种具有添加新功能能力的函数
装饰器必须遵循"开放封闭原则"
开放:对函数功能的添加是开放的, 意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况
封闭:对函数功能的修改是封闭的, 意味着对象一旦设计完成,就可以独立完成其工作,而不要对其进行修改
2.为什么要使用装饰器?
可以解决代码冗余问题,提高代码的可扩展性
3.怎么使用装饰器
可以通过闭包函数来实现装饰器
注意:使用装饰器要注意两点
不修改被装饰对象的源代码
不修改被装饰对象的调用方式
def download_movie(name): '''模拟电影下载''' print(f"电影{name}开始下载...") time.sleep(3) print(f"电影{name}下载完成...") return f'tank与{name}'# 添加统计时间的装饰器def time_out(func): def time_inner(*args, **kwargs): # 可以接受任何输入的值 start_time = time.time() # 收集开始时间 res = func(*args, **kwargs) # 接受源代码输入的任意值并收集返回值 end_time = time.time() # 收集结束时间 print(f'总时间{end_time - start_time}') # 计算时间并打印 return res return time_inner # 返回到闭包函数download_movie = time_out(download_movie) # 将download_movie赋值给funcdownload_movie('辛德勒的名单')
注意:
# 装饰器模版def warpper(func): def warpper_inner(*args, **kwargs): # 可以接收原函数传入的任意值 res = func(*args, **kwargs) # 同样 return res # 将原函数的返回时原封不动的返回去 return warpper_inner # 调用闭包函数def func1(): passfunc1 = warpper(func1)func1() # 本质运行的程序的是warpper_inner()
4.装饰器的语法糖(@)
装饰器的语法糖,是属于装饰器的。@: 装饰器的语法糖# 注意: 在使用装饰器语法糖时,装饰器必须定义在被装饰对象之上。
# 添加统计时间的装饰器def time_out(func): def time_inner(*args, **kwargs): # 可以接受任何输入的值 start_time = time.time() # 收集开始时间 res = func(*args, **kwargs) # 接受源代码输入的任意值并收集返回值 end_time = time.time() # 收集结束时间 print(f'总时间{end_time - start_time}') # 计算时间并打印 return res return time_inner # 返回到闭包函数@time_out # 调用语法糖, 注意装饰器在原函数之前def download_movie(name): '''模拟电影下载''' print(f"电影{name}开始下载...") time.sleep(3) print(f"电影{name}下载完成...") return f'tank与{name}'download_movie('辛德勒的名单') # 运行函数