闭包函数
什么是闭包函数:内部函数对外部函数作用域而非全局全局作用域中的变量引用,那么该函数就叫闭包函数
(闭包函数必须定义在函数内部,可以使用外层函数的名字)
闭包函数是函数嵌套,函数对象,名称空间与作用域的结合体
#直接传参 def func(number): print(number) func(10) >>10 #通过闭包传参 def outer(number): def inner(): #inner闭包函数 print(number) return inner #将inner当做参数返回 inner = outer(10) inner() >>10
闭包函数的应用: 为了装饰器做准备
函数体传值的方式:1.直接将值以参数的形式传入;2.将值包给函数
例子:
爬取某个网站,打印获取数据的长度
# 方式一 直接传参 import requests def spider_func(url): # 往url地址发送请求,获取响应数据 response = requests.get(url) # 必须接收url # 状态码 200 if response.status_code == 200: #获取当前url地址中文本长度 print(len(response.text)) #获取当前url地址所有文本 print(response.text) print(response.status_code) url = 'https://www.baidu.com' spider_func(url)
#方式二 通过闭包函数接受url地址,执行爬取函数 import requests def spider_func(url): def spider_inner(): response = requests.get(url) if response.status_code == 200: print(len(response.text)) return spider_inner spider_page = spider_func('https://www.baidu.com/') spider_page()
装饰器:装饰的工具
装饰器必须要遵循“开放封闭”原则
开放:对函数功能的添加是开放的
封闭:对函数功能的修改是封闭的
装饰器的作用:在不修改被装饰对象源代码与调用方式的前提下,添加新的功能
装饰器必须遵循:*不修改被装饰对象源代码 *不修改被装饰对象的调用方式
怎么使用装饰器:
装饰器的应用:*统计时间 *登录认证......
为什么使用装饰器:可以解决代码冗余,提高代码的可扩展性
编写编写装饰器:通过闭包函数编写
例子:
需求:统计电影的下载时间
import time def movie_download(): print('start download') time.sleep(3) print('download completed') return 'nmb' # start_time = time.time() # movie_download() # end_time = time.time() # print(f'time cost:{end_time-start_time}') #缺点:当有多个装饰对象时,需要编写多次统计时间代码,导致代码冗余 # 添加计时功能 def time_record(func): start_time = time.time() # movie_download() 若这么写 该功能只能给movie_download()使用 func() end_time = time.time() print(f'time cost:{end_time - start_time}') return None res = time_record(movie_download) print(res)
完善装饰器
import time def time_record(func): def inner(*args,**kwargs): # *args, **kwargs接收所有参数 start_time = time.time() # 将被装饰对象需要接收的任意参数 原封不动传给func --》 被装饰对象 res = func(*args,**kwargs) # func(url) ---> download_movie(url) end_time = time.time() print(f'time cost:{end_time-start_time}') return res return inner def movie_download(): print('start download') time.sleep(3) print('download completed') return 'nmb' movie_download = time_record(movie_download) movie_download()
装饰器语法糖:
在使用语法糖时,装饰器必须在被装饰对象前定义
import time def wrapper(func): def inner(*args,**kwargs): start_time = time.time() res = func(*args,**kwargs) end_time = time.time() print(f'{end_time-start_time}') return res return inner # 使用装饰器语法糖 @wrapper def func(): print('start') time.sleep(3) print('end') func() # 不使用语法糖 func = wrapper(func) func()
装饰器模板
def wrapper(func): def inner(*args,**kwargs): #功能输入区 res = func(*args,**kwargs) # 调用被装饰对象,得到返回值 #功能输入区 return res return inner def func(): pass func = wrapper(func) func()