Python学习-迭代器、生成器
迭代器
一、迭代器协议
- 对象必须提供一个next方法,执行该方法要么返回迭代中的下一页,或者抛出一个Stoplteration异常,终止迭代。
- 具有可迭代的对象。
- 一种实现迭代器的的约定。(如for循环、sum、min、max等)使用迭代器协议访问对象。
二、Python中强大的for循环机制
for循环的本质:循环所有的对象,全部使用迭代器协议。只要能被for循环遍历的都有一个_iter_()方法。
其实,严格意义来说(字符串、列表、字典、集合、文件对象都是不可迭代对象),只不过是使用了for循环。调用了它们内部的_iter_方法,把它们变成可迭代的对象。
1 l = [1,2,3] 2 #下标访问 3 print(l[0]) 4 print(l[1]) 5 print(l[2]) 6 print(l[3]) #超出边界报错,IndexError: list index out of range 7 #遵循迭代器协议访问方式 8 iter_test = l.__iter__() 9 print(iter_test) 10 print(iter_test.__next__()) 11 print(iter_test.__next__()) 12 print(iter_test.__next__()) 13 print(iter_test.__next__()) #超出边界值,抛出异常StopIteration 14 15 #用while来模拟for循环 16 Test_iter = l.__iter__() 17 while True: 18 try: 19 print(Test_iter.__next__()) 20 except StopIteration: 21 print("迭代结束!") 22 break
注:for循环帮助处理异常。
生成器
一种数据类型,自动实现迭代器协议,就是可迭代协议。
两种表现方式
- 函数
1 #生成器雏形 2 def test(): 3 yield 1 4 yield 2 5 g = test() 6 print(g.__next__()) 7 print(g.__next__())
运行结果:
1 1 2 2
2.生成器表达式
1 g =("egg %s"%i for i in range(5)) 2 print(g) 3 print(g.__next__()) 4 print(g.__next__()) 5 print(g.__next__()) 6 print(g.__next__()) 7 print(next(g)) 8 print(next(g)) 9 print(next(g))
运行结果:
1 print(next(g)) 2 StopIteration 3 <generator object <genexpr> at 0x0000000001DFEDB0> 4 egg 0 5 egg 1 6 egg 2 7 egg 3 8 egg 4
总结:
- 语法与常规函数类似,它们之间不同的是生成器使用yield返回一个值,而函数使用return返回值。
- 自动实现迭代器协议。
- 状态挂起,yield语句挂起生成器函数的状态,保留足够的信息,以便于下一次从当前位置执行。
- 生成器只能遍历一次。
例子:
1 {'name':'北京','population':30000} 2 {'name':'上海','population':35000} 3 {'name':'山东','population':30080} 4 {'name':'河北','population':30900} 5 {'name':'台湾','population':35600} 6 #统计上面文件中各个省所占的总人口的比例 7 def get_population(): 8 with open('人口普查','r',encoding = 'utf-8') as f: 9 for i in f: 10 yield i 11 #以生成器的方式获取文件信息 12 g = get_population() 13 s1 = eval(g.__next__())['population'] 14 print(s1) 15 all_pop = sum(eval(i)['population'] for i in g) 16 print(all_pop) 17 18 for p in g: 19 print('%s %%'%eval(p)['population']/all_pop)
3.三元表达式
1 name = "laj" 2 res = "SB" if name == "alex" else "shuaige" 3 print(res)
运行结果:
满足if条件,res为SB,不满足则为shuaige。
shuaige
4.列表解析
1 egg_list = [] 2 for i in range(10): 3 egg_list.append("egg %s"%i) 4 print(egg_list) 5 l1 =["egg %s"%i for i in range(10)] 6 print(l1) 7 l2 =["egg %s"%i for i in range(10) if i > 5] 8 print(l2) 9 l1 =["egg %s"%i for i in range(10) if i > 5 else i] #没有四元表达式,可以有两元
运行结果:
1 ['egg 0', 'egg 1', 'egg 2', 'egg 3', 'egg 4', 'egg 5', 'egg 6', 'egg 7', 'egg 8', 'egg 9'] 2 ['egg 0', 'egg 1', 'egg 2', 'egg 3', 'egg 4', 'egg 5', 'egg 6', 'egg 7', 'egg 8', 'egg 9'] 3 ['egg 6', 'egg 7', 'egg 8', 'egg 9']
装饰器
本质就是函数。
装饰就是修饰,修饰一下其他的函数,添加附加功能。
两个原则:
1、不修改被修饰函数的调用方式。
2、不修改被修饰函数的源代码。
知识储备:
装饰器 = 高阶函数+闭包+函数嵌套
高阶函数
1、函数接受的参数是一个函数名
2、函数的返回值是一个函数名
3、只需满足其中一个条件就可以称为高阶函数。
1 import time 2 def foo(): 3 time.sleep(1) 4 print('hello world') 5 def test1(func): 6 print(func) 7 start_time = time.time() 8 func() 9 stop_time = time.time() 10 print("函数运行的时间是%s"%(stop_time-start_time)) 11 test1(foo)
函数的嵌套
在函数内部定义函数
1 def father(name): 2 def son(): 3 print("我的爸爸是%s"%name) 4 son() #局部变量只能在局部调用 5 father("lqj")
闭包
函数作用域的一种体现
1 def father(auth_typer): 2 def son(): 3 #print("我的爸爸是%s"%name) 4 def grandson(): 5 print("我的爷爷是%s"%auth_typer) 6 grandson() 7 son() #局部变量只能在局部调用 8 father('xxoo')
搭建装饰器的框架
1 import time 2 def timer(func): 3 def wrapper(): 4 start_time = time.time() 5 res = func() #运行test 6 stop_time = time.time() 7 print('函数的运行时间为%s'%(stop_time-start_time)) 8 return res 9 return wrapper 10 @timer 11 def test(): 12 time.sleep(3) 13 print('函数运行完毕') 14 return '这是返回值' 15 #res = timer(test) #返回wraper的地址 16 #res() #执行wrapper 17 #test = timer(test) #返回wraper的地址 18 #test() #执行wrapper 19 #@timer 就相当于test = timer(test) 20 res = test() 21 print(res)
解压
1 a,b,c = (1,2,3) 2 print(a,b,c) 3 a,*_,c = (1,2,3,4,5,6) 4 print(a,c)
两个值交换
1 f1 = 1 2 f2 = 2 3 f1,f2 = f2,f1 4 print(f1,f2)
def father(auth_typer):
def son():
#print("我的爸爸是%s"%name)
def grandson():
print("我的爷爷是%s"%auth_typer)
grandson()
son() #局部变量只能在局部调用
father('xxoo')

浙公网安备 33010602011771号