day-04
一、 闭包函数
一 什么是闭包?
内部函数包含对外部作用域而非全局作用域的引用 #提示:之前我们都是通过参数将外部的值传给函数,闭包提供了另外一种思路,包起来喽,包起呦,包起来哇
示例:
def outter(): x=110 def inner(): print(x) return inner f=outter() #这里是把返回值赋值给f f() #然后在用f调用函数
二 闭包的意义与应用
#闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域 #应用领域:延迟计算(原来我们是传参,现在我们是包起来)
from urllib.request import urlopen #加载爬虫模块 def index(url): def get(): return urlopen(url).read() return get baidu=index('http://www.baidu.com') #传入函数参数 print(baidu().decode('utf-8'))
二、 装饰器
装饰器就是闭包函数的一种应用场景
开放封闭原则:对修改封闭,对扩展开放
二 什么是装饰器
装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。 强调装饰器的原则:1 不修改被装饰对象的源代码 2 不修改被装饰对象的调用方式 装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能
三 装饰器的使用
一个简单的装饰器案例
#inner是闭包函数,通过传值 把外面的index传给inner函数,然后计算时间
import time
def timmer(func): #func 就是被装饰对象的内存地址
# func=index
#时间闭包函数
def inner():
start_time = time.time()
func()
stop_time = time.time()
print('run time is %s' % (stop_time - start_time))
return inner #把内部函数返回出去,方便外面调用
@timmer #index=timmer(index) 这里调用方式使把正下方的函数名,传给timmer的参数,并且结果赋值给正下方的函数名 ,相当于调用inner函数,inner是闭包函数
def index():
time.sleep(3)
print("welcome to index page")
index()
解决home传参问题
#inner是闭包函数,通过传值 把外面的index传给inner函数,然后计算时间 import time def timmer(func): # func=index #时间闭包函数 def inner(*args,**kwargs): #这里用args 接受所有参数 start_time = time.time() func(*args,**kwargs) #这原样返回 stop_time = time.time() print('run time is %s' % (stop_time - start_time)) return inner #把内部函数返回出去,方便外面调用 @timmer #index=timmer(index) 这里调用方式使把正下方的函数名,传给timmer的参数,并且结果赋值给正下方的函数名 ,相当于调用inner函数,inner是闭包函数 # def index(): # time.sleep(3) # print("welcome to index page") # index() def home(name): time.sleep(3) print("welcome to home %s page"%(name)) home('sunkedong')
带有返回值的装饰器
#inner是闭包函数,通过传值 把外面的index传给inner函数,然后计算时间 import time def timmer(func): # func=index #时间闭包函数 def inner(*args,**kwargs): start_time = time.time() res=func(*args,**kwargs) stop_time = time.time() print('run time is %s' % (stop_time - start_time)) return res #这里的意思是把上面res保存的结果返回出去,在外面需要调用 return inner #把内部函数返回出去,方便外面调用 @timmer #index=timmer(index) 这里调用方式使把正下方的函数名,传给timmer的参数,并且结果赋值给正下方的函数名 ,相当于调用inner函数,inner是闭包函数 def index(): time.sleep(1) print("welcome to index page") return "index-res" #存一个测试的返回值 res=index() #把返回值保存到变量中 print(res)#打印,下面的home是一样的原理 @timmer def home(name): time.sleep(1) print("welcome to home %s page"%(name)) return "home-res" res=home('sunkedong') print(res)
用户登录装饰器
第一步
import time def login(func): # func=index def inner(*args,**kwargs): name=input('username>>').strip() pwd=input('password>>').strip() if name == "sunkd" and pwd == "sunkd": res=func(*args,**kwargs) return res return inner @login def index(): time.sleep(1) print("login success...") print("welcome to index page") return "index_ok" @login def home(name,age): time.sleep(1) print("login success...") print('welcome to %s home page,age is %s '%(name,age)) return "home_ok"home('sunkd',22)
index()
第二步、修复两次登录的bug
import time current_status={'user':None,'login_status':False} def login(func): # func=index def inner(*args,**kwargs): #下面是判断登录状态,如果字典有内容,并且为True 那么直接执行函数,否则跳到登录 if current_status['user'] and current_status['login_status'] == True: res = func(*args, **kwargs) return res else: name=input('username>>').strip() pwd=input('password>>').strip() if name == "sunkd" and pwd == "sunkd": print('login sucess.') #登录成功后,记录状态 res=func(*args,**kwargs) current_status['user']=name current_status['login_status']=True return res return inner @login def index(): time.sleep(1) print("welcome to index page") return "index_ok" @login def home(name,age): time.sleep(1) print('welcome to %s home page,age is %s '%(name,age)) return "home_ok" index() home('sunkd',22)
三、带参数的装饰器
import time current_status={'user':None,'login_status':False} def auth(user_type='mysql'): #这里可以定义一个默认参数。后面可以重新赋值。 # user_type='file' def login(func): def inner(*args,**kwargs): #下面是判断登录状态,如果字典有内容,并且为True 那么直接执行函数,否则跳到登录 if current_status['user'] and current_status['login_status'] == True: res = func(*args, **kwargs) return res if user_type == 'file': u='sunkd' p='sunkd' elif user_type == 'mysql': print('mysql auth') elif user_type == 'ldap': print('ldap auth') else: print('no fount the auth type') exit(2) #下面开始用户登录 name = input('username>>').strip() pwd = input('password>>').strip() if name == u and pwd == p : print('login sucess.') # 登录成功后,记录状态 res = func(*args, **kwargs) current_status['user'] = name current_status['login_status'] = True return res return inner return login #下面返回的其实还是inner的函数 @auth(user_type='file1') def index(): time.sleep(1) print("welcome to index page") return "index_ok" index() # #下面这种调用方式比较原始,做为理解使用 # index=auth(user_type='file')(index) #这里就重新赋值了。会打印file # index()
加多个装饰器
import time current_status={'user':None,'login_status':False} def timmer(func): def inner(*args,**kwargs): start_time=time.time() res=func(*args,**kwargs) stop_time=time.time() print('run time is :[%s]' %(stop_time-start_time)) return res return inner def auth(egine='file'): # egine='file' def wrapper(func): def inner(*args,**kwargs): if current_status['user'] and current_status['login_status']: res = func(*args, **kwargs) return res if egine == 'file': u='egon' p='123' elif egine == 'mysql': u = 'egon' p = '123' elif egine == 'ldap': u = 'egon' p = '123' else: pass name = input('username>>:').strip() pwd = input('password>>:').strip() if name == u and pwd == p: print('login successfull') current_status['user'] = name current_status['login_status'] = True res = func(*args, **kwargs) return res return inner return wrapper @timmer @auth(egine='ldap') #@wrapper #index=wrapper(timmer_inner) # @timmer #timmer_inner=timmer(index) def index(): time.sleep(3) print('welcome to index page') return 123 index() #inner()
三、迭代器
'''
1 什么叫迭代:迭代是一个重复过程,每次重复都是基于上一次的结果来的
2 为什么要用迭代器?
l=['a','b','c'] n=0 while n < len(l): print(l[n]) n+=1
- 对于序列类型:字符串,列表,元组,可以使用基于索引的迭代取值方式,而对于没有索引的类型,如字典,
集合、文件,这种方式不再适用,于是我们必须找出一种能不依赖于索引的取值方式,这就是迭代器
3 可迭代的对象:只要对象内置有__iter__方法,obj.__iter__
4 迭代器对象:对象既内置有__iter__方法,又内置有__next__,如文件对象
注意:可迭代对象不一定是迭代器对象,而迭代器对象一定是可迭代的对象
'''
#可迭代的对象
# 'hello'.__iter__ # [1,2].__iter__ # (1,2).__iter__ # {'a':1}.__iter__ # {1,2,3}.__iter__ #
#既是可迭代对象,又是迭代器对象
# open('a.txt','w').__iter__ # open('a.txt','w').__next__
# 迭代器对象执行__iter__得到的仍然是它本身
# dic={'a':1,'b':2,'c':3} # iter_dic=dic.__iter__() # # print(iter_dic.__iter__() is iter_dic)
# f=open('a.txt','w')
# print(f is f.__iter__())
#迭代器对象的用处
# dic={'a':1,'b':2,'c':3} # iter_dic=dic.__iter__() # print(iter_dic.__next__()) # print(next(iter_dic)) # print(next(iter_dic)) # print(next(iter_dic)) #StopIteration # with open('a.txt','r') as f: # print(next(f)) # print(next(f)) # print(next(f)) # l=[1,2,3,4,5] # iter_l=l.__iter__() # print(iter_l) # print(next(iter_l)) # print(next(iter_l)) # print(next(iter_l))
#基于迭代器对象的迭代取值(不依赖索引)
dic={'a':1,'b':2,'c':3} iter_dic=dic.__iter__() obj=range(1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) # list(obj) # while True: # try: # i=next(iter_dic) # print(i) # except StopIteration: # break # # for i in dic: #iter_dic=dic.__iter__() # print(i)
'''
迭代器的优缺点:
- 优点:
提供了一种统一的迭代取值方式,该方式不再依赖于索引
更节省内存
- 缺点:
无法统计长度
一次性的,只能往后走,不能往前退,无法获取指定位置的值
'''
from collections import Iterable,Iterator print(isinstance('hello',Iterable)) print(isinstance('hello',Iterator))
四、生成器
定义:只要函数内部出现yield关键字,那么再调用该函数,将不会立即执行函数体代码,会到到一个结果
该结果就是生成器对象
# # def func(): # print('===>first') # yield 1 # print('===>second') # yield 2 # print('====>third') # yield 3 # # # g=func() # print(g)
#生成器本质就是迭代器
# print(next(g)) # print(next(g)) # print(next(g)) # print(next(g)) # print(next(func())) # print(next(func())) # print(next(func()))
# for i in g: # print(i) # # for i in g: # print(i) # # for i in g: # print(i) '''
yield的功能:
- 为我们提供了一种自定义迭代器的方式
- 对比return,可以返回多次值,挂起函数的运行状态
'''
#自定义功能,可以生成无穷多个值,因为同一时间在内存中只有一个值
# def my_range(start,stop,step=1): # while start < stop: # yield start # start+=step # g=my_range(1,5,2) #1 3 # print(next(g)) # print(next(g)) # print(next(g)) # print(next(g)) # print(next(g)) # # for i in my_range(1,1000000000000000000000000000000000000000000,step=2): # print(i) # tail -f access.log | grep '404' # import time # def tail(filepath): # with open(filepath,'rb') as f: # f.seek(0,2) # while True: # line=f.readline() # if line: # yield line # else: # time.sleep(0.2) # # def grep(pattern,lines): # for line in lines: # line=line.decode('utf-8') # if pattern in line: # yield line # # g=grep('404',tail('access.log')) # for line in g: # print(line)
#yield的表达式形式的应用
# def eater(name): # food_list=[] # print('%s 开动啦' %name) # while True: # food=yield food_list #food=‘骨头’ # print('%s 开始吃 %s' %(name,food)) # food_list.append(food) # # g=eater('alex') # g.send(None) #next(g) # print(g.send('骨头')) # print(g.send('shi')) # def f1(): # while True: # x=yield # print(x) # # g=f1() # next(g) # g.send(1) # g.send(1) # g.close() # g.send(1) # g.send(1) # g.send(1)
二元表达式
def my_max(x,y): return x if x > y else y
列表解析 与生成器表达式
egg_list=[] for i in range(10): if i >= 3: res='egg%s' %i egg_list.append(res) names=['egon','alex_sb','wupeiqi','yuanhao'] names=[name.upper() for name in names if not name.endswith('sb')] print(names)
#1、把列表推导式的[]换成()就是生成器表达式 #2、示例:生一筐鸡蛋变成给你一只老母鸡,用的时候就下蛋,这也是生成器的特性 >>> chicken=('鸡蛋%s' %i for i in range(5)) >>> chicken <generator object <genexpr> at 0x10143f200> >>> next(chicken) '鸡蛋0' >>> list(chicken) #因chicken可迭代,因而可以转成列表 ['鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4',] #3、优点:省内存,一次只产生一个值在内存中