1.1迭代器
什么是迭代器:
迭代器是一个可以记住遍历的位置对象
迭代器对象从集合的第一个元素元素开始访问,直到所有元素被访问完结束,迭代器只能往前不会后退。
迭代器有两个基本方法:iter ,next 方法
内置函数iter(),next() 本质上都是用的对象.__iter__(),__next__()的方法
内置函数 iter(iterable),表示把可迭代对象 变成迭代器(iterator)
内置函数next(iterator) ,表示查看下一次迭代的值(当然也可以用 iterator.__next__() ,查看下一次迭代的值)
1.1.2迭代器协议
1.迭代器(iterator)协议是指:对象必须提供一共next方法,执行该方法妖魔返回迭代中的下一项,要么就引起一个Stopiteration异常,已终止迭代。
2.可迭代对象:实现了迭代器协议的对象,(该对象内部定义了一个__iter__()的方法 例:str.__iter__())就是可迭代对象
3.协议是一种约定,可迭代对象实现了迭代器协议,python的内部工具(如。for循环,sum,min,max函数等)使用迭代器协议访问对象
1.1.3python中的for循环
for循环本质:循环所有对象,全部是使用迭代器协议
(字符串,列表,元祖,字典,集合,文件对象),这些都不是可迭代对象,只不过在for循环,调用了他们内部的__iter__方法,把他们变成了可迭代对象。然后for循环调用可迭代对象的__next__方法去去找,然后for循环会自动捕捉StopIteration异常,来终止循环。
1 l1 = ["hello","world",1,2] 2 3 #for循环调用可迭代对象的__next__方法去取值,而且for循环会捕捉StopIteration异常,以终止对象 4 for i in l1: 5 print(i) 6 7 aa = l1.__iter__() #等同于内置函数aa = iter(l1) 创建了一个list_iterator 列表迭代器 8 print(type(aa)) 9 print(next(aa)) #内置函数 next()查看第一次迭代器的值 10 print(aa.__next__()) #迭代器本身对象的方法,第二次迭代器的值 跟 内置函数方法都是一样的 11 print(next(aa)) 12 print(next(aa)) 13 print(next(aa)) #没有可迭代的值了也就是迭代完了,会报错:StopIteration 14 15 16 #迭代器迭代完,就不能再次迭代该迭代器 比如for 循环 17 for i in aa: 18 print(i)
1 # 首先获得Iterator对象: 2 it = iter([1, 2, 3, 4, 5]) #创建一个迭代器 3 # 循环: 4 while True: 5 try: 6 # 获得下一个值: 7 x = next(it) 8 print(x) 9 except StopIteration: 10 # 遇到StopIteration就退出循环 11 break
总结:
1.可作用于for循环对象本身都是iterable(可迭代对象)类型,或者对象本身有obj.__iter__方法也是iterable
2.凡是可作用于next()函数的对象本身itertor(迭代器)类型,或者obj.__next__也是iterator ,迭代器是一个惰性序列
因为需要调用next,才会获得元素,迭代完,就不能再次迭代。
3.list、dict、str等是iterable,但不是iterator不过可以通过iter()函数获得一个迭代器对象。
1.2生成器
什么是生成器?
1.从字面理解是不是:生成一个容器
2.在python中,一边循环,一边计算的机制,称为生成器(generator)。
3.可以理解为一种数据类型,这种类型自动实现了迭代器协议。(其他的数据类型需要调用自已的内置__iter__方法或则iter()的内置函数),所以生成器就是一个可迭代对象。
生成器分类以及在python中的表现形式。(python有两种不同的方式提供生成器)
1.生成器函数:常规函数定义,但是,使用yield语句而不是return语句的返回结果。yield语句一次返回一个结果,在每个结果中间,保留函数的状态,以便再上一次状态的重新执行。
2.生成器表达式:类似于列表推导,但是生成器返回按需产生结果的一种对象,而不是一次构建一个结果列表
为何使用生成器,生成器的优点:
python使用生成器对延迟操作提供了支持。所谓延迟操作,是指需要的时候才产生结果,而不是立即生成结果
这就是生成器的好处
生成器小结:
1.生成器是可迭代对象
2.实现了延迟计算,看内存(按需,执行)
3.生成器本质和其他类型一样,都是实现了迭代器协议,只不过生成器是一边计算,一边生成,从而节省内存空间,
其余的可迭代对象可没有好处。
定义生成器的前提:
1.考虑这个生成器是否需要多次遍历。
2.这个生成器内存空间的问题。
3.时间效率问题。
生成器是一个惰性的,根据惰性求值:也就是需要一个对象给一个对象
1.2.1生成器表达式、列表生成式、三元表达式
1.三元运算或则3元表达式
1 #三元表达式格式 2 3 res=值1 if 条件 else 值2 4 5 #如果条件满足 res 等于 值1 条件不满足就等于 值2 6 # demo 1 7 name = "xixi" 8 res = "xixi" if name == "xixi" else "hello" 9 print(res) 10 11 #demo 2 12 num = 2 if False else 0 13 print(num)
2.列表生成式
1 #列表生成式通过计算生成一个列表 2 3 lis_gen = [ i for i in range(1,10)] #列表生成式 4 print(lis_gen) 5 6 lis1_gen = [i for i in range(1,10) if i%2 == 0] #生成一个偶数的列表 7 print(lis1_gen) 8 9 lis2_gen = [ i * i for i in range(1,10) if i%2 == 1] #生成以个奇数乘自已本身奇数的列表 10 print(lis2_gen)
3.生成器表达式
1 gen_exp = (i for i in range(10)) #生成器表达式 2 print(gen_exp) #generator 3 # for i in gen_exp: #取出生成器表达式的值,for循环 4 # print(i) 5 print(gen_exp.__next__()) #next方法 6 print(gen_exp.__next__()) 7 print(gen_exp.__next__()) 8 print(gen_exp.__next__()) 9 print(gen_exp.__next__())
1 gen = (i for i in range(10**100)) #生成器表达式 2 lis = [i for i in range(10**100)] #列表生成式 3 4 #生成器,更省内存,需要一个取一个 5 print(gen.__next__()) 6 print(lis) #需要在内存空间创建1-10**100序列
总结:
1.把列表解析的[]换成()得到就是生成器表达式
2.列表生成式式一个构建一个结果列表,生成器表达式:是返回按需产生结果的一个对象
3.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存
4.python不但使用迭代器协议让for循环更加通用,大部分内置函数,也是使用迭代器协议访问对象的
如,sum函数是python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议
1.2.2生成器函数
在python中,使用了yield的函数就称为生成器(generator)
1.跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,可以理解为:生成器就是一个迭代器
2.在调用生成器运行过程中,每次遇到yield是函数会暂停并保存当前所有的运行信息,返回yield值。并在下一次执行next方法时,从当前位置继续运行。
普通生成器:
1 >>> gen = (i for i in range(5)) 2 >>> gen 3 <generator object <genexpr> at 0x0000004DE29A70A0> 4 >>> next(gen) 5 0 6 >>> next(gen) 7 1 8 >>> next(gen) 9 2 10 >>> next(gen) 11 3 12 >>> next(gen) 13 4 14 >>> next(gen) 15 Traceback (most recent call last): 16 File "<stdin>", line 1, in <module> 17 StopIteration
注:generator保存的是算法,每次调用next方法,就计算出gen的下一个元素的值,直到计算到最后一个元素,没有更多元素时,就StopIteration的错误。
当然,上面这种不断调用next(gen),用着有点坑,正确的方法是使用for循环,因为generator也是iterator;
1 >>> g = (i for i in range(5)) 2 >>> for i in g: 3 ... print(i) 4 ... 5 0 6 1 7 2 8 3 9 4
所以我们创建了一个generator后,基本不会调用next方法,而是通过for循环来迭代它,并且不是关心StopIteration的错误。
generator非常强大,如果计算的算法比较复杂,用for循环无法实现的时候,还可以用函数来实现。
例:斐波拉契数列 后面的一个数等于前面两个数相加的和
1 def fib(number): 2 #得出几个斐波拉契数列 3 count,a,b = 0,0,1 4 while count < number: 5 print(b) 6 a,b = b,a+b 7 count += 1 8 return "done" 9 fib(5)
1 def fib1(number): 2 n,a,b = 0,0,1 3 while n<number: 4 yield b 5 a,b = b,a+b 6 n += 1 7 return "done" 8 aa = fib1(6) 9 print(aa) #generator 10 # print(aa.__next__()) 11 for i in aa: 12 print(i)
注:如果一个函数定义中包含yield关键字,那么这个函数就不是普通函数,而是一个generator
注:generator和函数执行的流程不一样,
函数是顺序执行,遇到return语句或则最后一行函数函数语句就返回。
而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行从上次返回的yield语句处继续执行
1 def packet(): 2 for i in range(1,10): 3 print("开始生产包子") 4 yield "第 %d 屉包子" %(i) 5 print("卖包子,买完再生产") 6 cs = packet() #生成一个做包子的生成器,相当于做包子的 7 # print(cs) 8 q = print(cs.__next__()) #卖包子的 9 print(cs.__next__()) 10 for i in cs: 11 print(i)
1 #单线程一边发送,一边执行 2 import time 3 def consumer(name): 4 print("%s 准备吃包子啦!" %name) 5 while True: 6 baozi = yield 7 8 print("包子[%s]来了,被[%s]吃了!" %(baozi,name)) 9 def producer(name): 10 c = consumer(‘A‘) 11 c2 = consumer(‘B‘) 12 c.__next__() 13 c2.__next__() 14 print("老子开始准备做包子啦!") 15 for i in range(10): 16 time.sleep(1) 17 print("做了2个包子!") 18 c.send(i) #发送的值,就是yield的返回值 19 c2.send(i) 20 producer("xixi")
1.2.3生成器函数总结
1.生成器函数语法上和普通函数类似:生成器使用yield语句返回一个值,而常规函数使用return语句返回一个值
2.生成器自动实现迭代器协议,迭代完,就不能再次迭代。
3.状态挂起:生成器使用yield语句返回一个值。挂起该生成器函数的状态。
1.3装饰器(decorator)
什么是装饰器:
器即函数
1.装饰器可以理解为给一个函数,做修饰,而不修改函数本身。
2.装饰器定义:本质就是函数,decorator功能就是为其他函数添加新的功能。
装饰器的的原则
装饰器=高阶函数+函数嵌套+闭包
装饰器的前提原则:不能修改被装饰函数的源代码,和函数的调用方式
1.1.1高阶函数
高阶函数定义:
1.函数接收的参数是一个函数名。
2.函数的返回值是一个函数。
3.满足上述条件任意一个,都是高阶函数
1.1.2函数嵌套
函数嵌套
python语言中的嵌套:定义一个函数的时候,函数体还能定义另一个函数。
在其他语言(例c语言),在一个函数调用另一个函数,叫嵌套
1.1.3闭包
存储在子封闭作用域(函数)的行为叫做闭包
一个闭包就是一个函数,只不过函数内部带上了一个额外的变量。
闭包关键特点就是它会记住自已被定义时的环境
1.2一步一步理解装饰器
1 def go(): 2 print("python") 3 #该函数功能执行go() ,显示出python 4 go()
现在我们要增强go()这个自定义函数的功能,比如在函数调用前自动打印出python是什么样的语言,但有不想在修改go()函数,这种在代码运行期间动态为其添加功能,就称之为装饰器(decorator)。
1.现在给go()函数加功能
1 #一个装饰器的基本框架 2 def deco(func): 3 def wrapper(): 4 func() #执行你传的go的函数 5 print("一个高级语言") 6 return wrapper 7 def go(): 8 print("python") 9 go = deco(go) #得到结果wrappe的函数r 10 go() # 执行wrapper函数 ——执行函数func() 函数也就是的go()函数 11 #结果 12 python 13 一个高级语言 14 15 #上面就是一个装饰器功能的基本体现,没有修改go函数的源代码,也没有修改go()函数的执行方式,也给go函数加上了一个新功能(高级语言) ,
但是上面每次执行,都需要做一个函数赋值操作,才能执行go() ,这是不完美的
本质上:装饰器(decrator)就是一个返回函数的高阶函数,上面的deco,就是一个装饰器,接收函数做参数,并返回一个函数,需要借助python的@语法,@装饰器
1 def deco(func): 2 def wrapper(): 3 func() 4 print("一个高级语言") 5 return wrapper 6 @deco 7 def go(): 8 print("python") 9 go() 10 #结果 11 python 12 一个高级语言 13 14 #现在才相当于一个合格的装饰器 15 16 把@deco放到go()函数的定义处,相当于执行了go=deco(go)
上面deco()是一个装饰器,返回一个函数,所以原来的go()函数仍然存在,
只是现在同名的go变量指向了新的函数,于是调用go()函数将执行新函数,
即在go()函数中返回的wrapper()函数
2.给被装饰器函数加参数和返回值
1 def deco(func): 2 def wrapper(*args,**kwargs): 3 res = func(*args,**kwargs) #这里就相当于闭包 4 print("一门高级语言") 5 return res 6 return wrapper 7 8 @deco 9 def go(x,y): 10 print("python",x,y) 11 return "done" 12 go(3,5) 13 # 结果 14 python 15 一个高级语言 16 17 # 为什么要给装饰器加参数,如果被装饰的函数里面有参数,我们的装饰器是不是器也要加相应的参数, 18 我们的装饰器为什么要给wrapper(*args,**kwargs) func(*args,**kwargs),可接收任意参数,因为我们被装饰的函数可能都是不同的的参数,而这个装饰器,需要给很多函数做装饰,但是很多函数的参数,功能都是不一样的,因此我们定义装饰器 的函数参数应该是加可变长参数 19 20 #为什么给装饰里面加返回值 21 我们被装饰的函数,一般是有返回值,而执行装饰器(@decorator) 所以需要给wrapper 加上返回值来return fun()的执行结果,来保持被装饰的函数的一致性。
3.给装饰器加参数
如果装饰器本身需要传入参数,那就需要编写一个返回装饰器的高阶函数,也就是在原来装饰器上,做闭包处理,在加上一层函数。
1 def auth_book(auth=None): 2 print(auth) 3 def deco(func): 4 def wrapper(*args,**kwargs): 5 res = func(*args,**kwargs) #这里就相当于闭包 6 print("一门高级语言") 7 return res 8 return wrapper 9 return deco 10 @deco("book") #装饰器加参数 跟go=deco("book")(go)类似 11 def go(x,y): 12 print("python",x,y) 13 go(3,5)
3层嵌套的装饰器的效果是这样的
1 go=auth_book("book")(go)
1 user_list=[ 2 {‘name‘:‘yj‘,‘passwd‘:‘123‘}, 3 {‘name‘:‘xixi‘,‘passwd‘:‘123‘}, 4 {‘name‘:‘xiha‘,‘passwd‘:‘123‘}, 5 {‘name‘:‘lala‘,‘passwd‘:‘123‘}, 6 ] 7 8 current_user={‘username‘:None,‘login‘:False} 9 def auth(auth_type=‘file‘): 10 def auth_deco(func): 11 def wrapper(*args,**kwargs): 12 if auth_type == ‘file‘: 13 if current_user[‘username‘] and current_user[‘login‘]: 14 res=func(*args,**kwargs) 15 return res 16 username=input(‘用户名: ‘).strip() 17 passwd=input(‘密码: ‘).strip() 18 19 for index,user_dic in enumerate(user_list): 20 if username == user_dic[‘name‘] and passwd == user_dic[‘passwd‘]: 21 current_user[‘username‘]=username 22 current_user[‘login‘]=True 23 res=func(*args,**kwargs) 24 return res 25 26 else: 27 print(‘用户名或者密码错误,重新登录‘) 28 elif auth_type == ‘ldap‘: 29 print(‘巴拉巴拉小魔仙‘) 30 res=func(*args,**kwargs) 31 return res 32 return wrapper 33 return auth_deco 34 35 36 #auth(auth_type=‘file‘)就是在运行一个函数,然后返回auth_deco,所以@auth(auth_type=‘file‘) 37 #就相当于@auth_deco,只不过现在,我们的auth_deco作为一个闭包的应用,外层的包auth给它留了一个auth_type=‘file‘参数 38 @auth(auth_type=‘ldap‘) 39 def index(): 40 print(‘欢迎来到主页面‘) 41 42 @auth(auth_type=‘ldap‘) 43 def home(): 44 print(‘这里是你家‘) 45 @auth(auth_type="file") 46 def shopping_car(): 47 print(‘查看购物车啊亲‘) 48 49 def order(): 50 print(‘查看订单啊亲‘) 51 52 # print(user_list) 53 index() 54 # print(user_list) 55 home() 56 shopping_car()