闭包函数
'''闭包函数:
1、闭包函数必须在函数内部定义
2、闭包函数可以引用外层函数的名字
闭包函数是函数对象、函数嵌套、名称空间与作用域的结合体'''
#直接传参
deffunc(x):print(x)#通过闭包函数传参
defwrapper(x):definner():print(x)returninner
func= wrapper(100) #>>返回inner的内存地址>>>>保存在func中
func()
闭包函数定义
#闭包函数的应用
importrequests#直接传参
defspider_func(url):
response=requests.get(url)if response.status_code == 200:print(len(response.text))#闭包函数chuanc
defspider_outer(url):defspider_inner():
response=requests.get(url)if response.status_code == 200:print(len(response.text))returnspider_inner
url1= 'https://www.baidu.com/'url2= 'https://www.cnblogs.com/xiaoyuanqujing'spider_baidu=spider_outer(url1)
spider_blog=spider_outer(url2)
spider_baidu()
spider_blog()
spider_outer(url1)
闭包函数的应用
装饰器
'''装饰器
不修改原函数的源代码
不修改原函数的调用方式
被装饰对象:即需要添加功能的函数
装饰器:被装饰函数添加的新功能的函数'''
例子:假设我们现在有一个函数,我们要为其添加一个统计执行时间的功能
defdownload_movie():print('Start downloading.....')
time.sleep(3)print('Download completed.....')
讲道理我们是这么执行的
#不使用装饰器
start_time =time.time()
download_movie()
stop_time=time.time()print(f'Running time is {stop_time - start_time}....')
问题虽然解决了,但针对每个需要添加统计时间功能的函数,都得敲一遍代码。这显然不符合python所要求的简洁优雅~
所以我们考虑:
#使用装饰器(无返回值时)
deftimer(func):definner():
start_time=time.time()
func()#>>>>>被装饰对象<<<<<
stop_time =time.time()print(f'Running time is {stop_time - start_time}....')returninner
timer(download_movie)#>>>>>>>>>> 返回inner
download_movie = timer(download_movie) #>>>>>>>>>>>以变量名download_movive接收inner
download_movie()
问题似乎解决了,然鹅,如果被装饰对象有返回值,如:
defdownload_movie():print('Start downloading.....')
time.sleep(3)print('Download completed.....')return 'Aoi.avi' #当被装饰对象有返回值时,上述装饰器需做修改
我们好像就得不到被装饰对象执行结束后返回的值的,这显然没有什么软用。于是修改装饰器
deftimer(func):definner():
start_time=time.time()
res= func() #>>>>>>>>>>>用res接收func()产生的返回值<<<<<<<<<<<<<<<
stop_time =time.time()print(f'Running time is {stop_time - start_time}....')return res #返回>>>>>>>>>>res<<<<<<<<<< (本例子中即download_movie的返回值)
returninner
download_movie=timer(download_movie)print(download_movie()) #>>> Aoi.avi
问题好像又解决了,然鹅,如果被装饰对象有参数,如:
#使用装饰器(被装饰对象有参数)
defdownload_movie(url):print(f'From {url}\nStart downloading........')
time.sleep(3)print(f'Download completed')如果还是 download_movie = timer(download_movie)
download_movie(url) >>>>>># 会报错,因为download实际上是inner的别名。调用的是inner(url)
于是修改装饰器:
deftimer(func):definner(url):
start_time=time.time()
func(url)#从闭包函数inner获取参数
stop_time =time.time()print(f'Running time is {stop_time - start_time}....')returninner
download_movie= timer(download_movie) #>>>>>返回inner >>>>>>更名为download_movie
download_movie('https://www.baidu.com/')
问题好像又解决了,然鹅,如果不确定被装饰对象的参数个数那又该怎么办呢?
修改装饰器,最终版本:
deftimer(func):def inner(*args, **kwargs):
start_time=time.time()
res= func(*args, **kwargs) #>>>>>>>>>>>用res接收func()产生的返回值<<<<<<<<<<<<<<<
stop_time =time.time()print(f'Running time is {stop_time - start_time}....')return res #返回>>>>>>>>>>res<<<<<<<<<< (本例子中即download_movie的返回值)
return inner
解决~~~~
欸,等下~~~~~~~~~~~这装饰器用起来还是有点麻烦啊
python大佬为我们提供了更简洁的装饰器调用方式。装饰器语法糖@
deftimer(func):def inner(*args, **kwargs):
start_time=time.time()
res= func(*args, **kwargs) #>>>>>>>>>>>用res接收func()产生的返回值<<<<<<<<<<<<<<<
stop_time =time.time()print(f'Running time is {stop_time - start_time}....')return res #返回>>>>>>>>>>res<<<<<<<<<< (本例子中即download_movie的返回值)
returninner
@timerdeffunc():print('hello world')#当我们调用func()时
func()#等价于 func = timer(func) func()