一、闭包
闭包:内层函数对外层函数非全局的变量的引用
好处:如果python检测到闭包,他有一个机制,你的局部作用域不会随着函数结束而结束。他会一直在内存当中
判断闭包的方法:返回cell 是闭包 ;返回None 不是闭包
闭包的应用:装饰器
1 #例1 闭包 2 def wrapper(): 3 name1='老男孩' 4 def inner (): 5 print(name1) 6 inner() 7 print(inner.__closure__) 8 wrapper() 9 # >>>老男孩 10 # >>>(<cell at 0x0000022AFAC075E8: str object at 0x0000022AFAC9F750>,) 11 12 #例2 不是闭包 13 name1='老男孩' 14 def wrapper(): 15 def inner (): 16 print(name1) 17 inner() 18 print(inner.__closure__) 19 wrapper() 20 # #>>>老男孩 21 # #>>>None 22 23 #例3 判断以下代码是不是闭包 24 def wrapper(argv):#通过参数传也是闭包 25 def inner(): 26 print(argv) 27 inner() 28 print(inner.__closure__) 29 wrapper('老男孩') 30 # 老男孩 31 # >>>(<cell at 0x0000022AFAC075E8: str object at 0x0000022AFAC9F750>,) 32 33 #例4 闭包的好处 34 # 1、如果爬取得数据量比较大时,如果没有闭包机制,每次爬取得内容都会占用内存,但是有闭包的机制,第一次爬取时已经读到内存,以后爬取时都是从内存的读到的数据,并不是从url在爬取一次 35 #2、装饰器,装饰器的基本原理就是通过闭包实现的不用担心爬取的内容会一直占用内存,python内部有垃圾回收机制,如果内存在一定时间没有用,会自动在内存中关闭 36 #垃圾回收机制,有一个类似于计数器,记录所有的变量,超过固定的时间没有用,在内存中清除 37 from urllib.request import urlopen 38 39 def index(): 40 url = "http://www.xiaohua100.cn/index.html" 41 def get(): 42 return urlopen(url).read()#urlopen(url).read()意思是将url所有内容读取出来 43 return get 44 45 content1=index()() 46 content2=index()()#第二次执行函数时,是从内存中读取的数据,不会 重新将url的内容重新在读一遍 47 print(content1)
二、装饰器
装饰器:在不改变原函数即原函数的调用的情况下,为原函数增加一些额外的功能。例如:打印日志、执行时间、登录认证等等。
1、两种方式把下列代码中的inner()函数执行:
1 def wrapper(): 2 def inner(): 3 name1='alex' 4 print(name1) 5 #以下两种方法就是在函数外面如何执行函数内嵌的方法 6 #方法一 7 def wrapper(): 8 def inner(): 9 name1='alex' 10 print(name1) 11 inner() 12 wrapper()#>>>alex 13 #方法二 14 def wrapper(): 15 def inner(): 16 name1='alex' 17 print(name1) 18 return inner 19 wrapper()()#>>>alex
2、下面说装饰器,测试函数的执行效率的方法,以下代码改变了原来函数的执行方式:
1 import time 2 def func1(): 3 print('老男孩') 4 time.sleep(0.3) 5 def func2(): 6 print('oldboy') 7 time.sleep(0.3) 8 9 def timer(f1): 10 strat_time=time.time()#当前的时间,距离1970年1月1号 整12点的时间 11 f1() 12 end_time=time.time() 13 print('此函数的执行效率:%s'%(end_time - strat_time)) 14 15 timer(func1) 16 timer(func2)
3、最简单版的装饰器
1 import time 2 def func1(): 3 print('老男孩') 4 time.sleep(0.3) 5 6 def timer(f1): 7 def inner(): 8 strat_time=time.time()#当前的时间,距离1970年1月1号 整12点的时间 9 f1() 10 end_time=time.time() 11 print('此函数的执行效率:%s'%(end_time - strat_time)) 12 return inner 13 ''' 14 f=func1 15 func1=timer 16 func1(f) 17 ''' 18 func1=timer(func1)#相当于inner 19 func1()#相当于inner()
4、@修饰符
作用:直接运行代码中被修饰的函数
1 import time 2 def timer(f1): 3 def inner(): 4 strat_time=time.time()#当前的时间,距离1970年1月1号 整12点的时间 5 f1() 6 end_time=time.time() 7 print('此函数的执行效率:%s'%(end_time - strat_time)) 8 return inner 9 10 @timer #相当于func1=timer(func1) 11 def func1(): 12 print('老男孩') 13 time.sleep(0.3) 14 func1() 15 16 @timer #相当于func2=timer(func2) 17 def func2(): 18 print('oldboy') 19 time.sleep(0.3) 20 func2()
5、带参数的装饰器(被装饰的函数带参数)
1 import time 2 def timer(f1): 3 def inner(*args,**kwargs): 4 strat_time=time.time()#当前的时间,距离1970年1月1号 整12点的时间 5 f1(*args,**kwargs) 6 end_time=time.time() 7 print('此函数的执行效率:%s'%(end_time - strat_time)) 8 return inner 9 10 @timer #相当于func1=timer(func1) 11 def func1(a,b): 12 print(a,b) 13 print('老男孩') 14 time.sleep(0.3) 15 func1(111,222)
6、带返回值的装饰器
1 import time 2 def timer(f1): 3 def inner(*args,**kwargs): 4 strat_time=time.time()#当前的时间,距离1970年1月1号 整12点的时间 5 ret=f1(*args,**kwargs) 6 end_time=time.time() 7 print('此函数的执行效率:%s'%(end_time - strat_time)) 8 return ret 9 return inner 10 11 @timer #相当于func1=timer(func1) 12 def func1(a,b): 13 print(a,b) 14 print('老男孩') 15 time.sleep(0.3) 16 return 666 17 print(func1(111,222))
7、装饰器雏形
1 def wapper(f1): 2 def inner(*args,**kwargs): 3 '''执行函数之前的操作''' 4 ret=f1(*args,**kwargs) 5 '''执行函数之后的操作''' 6 return ret 7 return f1 8 @wapper 9 def func1(): 10 print(222) 11 func1()