闭包函数

''' 闭包函数: 1、闭包函数必须在函数内部定义 2、闭包函数可以引用外层函数的名字 闭包函数是函数对象、函数嵌套、名称空间与作用域的结合体 ''' # 直接传参 def func(x): print(x) # 通过闭包函数传参 def wrapper(x): def inner(): print(x) return inner func = wrapper(100) # >>返回inner的内存地址>>>>保存在func中 func()

# 闭包函数的应用 import requests # 直接传参 def spider_func(url): response = requests.get(url) if response.status_code == 200: print(len(response.text)) # 闭包函数chuanc def spider_outer(url): def spider_inner(): response = requests.get(url) if response.status_code == 200: print(len(response.text)) return spider_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)
装饰器
''' 装饰器 不修改原函数的源代码 不修改原函数的调用方式 被装饰对象:即需要添加功能的函数 装饰器:被装饰函数添加的新功能的函数 '''
例子:假设我们现在有一个函数,我们要为其添加一个统计执行时间的功能
def download_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所要求的简洁优雅~
所以我们考虑:
# 使用装饰器(无返回值时) def timer(func): def inner(): start_time = time.time() func() # >>>>>被装饰对象<<<<< stop_time = time.time() print(f'Running time is {stop_time - start_time}....') return inner timer(download_movie) # >>>>>>>>>> 返回inner download_movie = timer(download_movie) # >>>>>>>>>>>以变量名download_movive接收inner download_movie()
问题似乎解决了,然鹅,如果被装饰对象有返回值,如:
def download_movie(): print('Start downloading.....') time.sleep(3) print('Download completed.....') return 'Aoi.avi' # 当被装饰对象有返回值时,上述装饰器需做修改
我们好像就得不到被装饰对象执行结束后返回的值的,这显然没有什么软用。于是修改装饰器
def timer(func): def inner(): 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的返回值) return inner download_movie = timer(download_movie) print(download_movie()) # >>> Aoi.avi
问题好像又解决了,然鹅,如果被装饰对象有参数,如:
# 使用装饰器(被装饰对象有参数) def download_movie(url): print(f'From {url} Start downloading........') time.sleep(3) print(f'Download completed')
如果还是 download_movie = timer(download_movie)
download_movie(url) >>>>>># 会报错,因为download实际上是inner的别名。调用的是inner(url)
于是修改装饰器:
def timer(func): def inner(url): start_time = time.time() func(url) # 从闭包函数inner获取参数 stop_time = time.time() print(f'Running time is {stop_time - start_time}....') return inner download_movie = timer(download_movie) # >>>>>返回inner >>>>>>更名为download_movie download_movie('https://www.baidu.com/')
问题好像又解决了,然鹅,如果不确定被装饰对象的参数个数那又该怎么办呢?
修改装饰器,最终版本:
def timer(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大佬为我们提供了更简洁的装饰器调用方式。装饰器语法糖@
def timer(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 @timer def func(): print('hello world') # 当我们调用func()时 func() # 等价于 func = timer(func) func()