Python Day 13 函数(迭代器,生成器,列表推导式,生成器表达式)
可迭代对象
内部含有__iter__方法的就是可迭代对象,遵循可迭代协议。实际上可迭代对象是不可以依次取值的,因为他没有__next__方法。
for循环提供一个机制:
1,将可迭代对象转化成迭代器。
2,利用__next__进行取值。
3,用try异常处理方法防止报错。
模拟for循环
l = [1, 2, 3, 4, 5] l_obj = l.__iter__() while True: try: print(l_obj.__next__()) except Exception: break
判断方法
第一种方法:dir
dir print(dir('123')) # '__iter__' print('__iter__' in dir([1, 2, 3])) print('__iter__' in dir({'name':'alex'})) print('__iter__' in dir({'name'})) print('__iter__' in dir((1, 2, 3))) print('__iter__' in dir(1)) # False print('__iter__' in dir(True)) # False
第二种方法:引入方法
from collections import Iterable
from collections import Iterator
from collections import Iterable from collections import Iterator print(isinstance('123', Iterable)) print(isinstance('123', Iterator))
迭代器 iterator
可迭代对象通过.__iter__()可以转换成迭代器,满足迭代器协议。内部含有__iter__ 且 __next__方法的就是迭代器。
1,节省内存。
2,满足惰性机制。
3,取值过程不可逆(一条路走到黑)。
迭代器的取值两种方法:
方法一:__next__()
print(l_obj.__next__()) print(l_obj.__next__()) print(l_obj.__next__()) print(l_obj.__next__())
方法二 for循环
for i in l_obj: print(i) print('__next__' in dir(l_obj))
生成器 Generator:
生成器本质也是迭代器,生成器是自己用Python写的迭代器。
构建方法:
1,通过生成器函数构建。
一个包含yield关键字的函数就是一个生成器函数。yield可以为我们从函数中返回值,
但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,
而是得到一个可迭代的对象。每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。
send
2,通过生成器推导式构建。
def generator(): print(123) content = yield 1 print('=======',content) print(456) yield2 g = generator() ret = g.__next__() print('***',ret) ret = g.send('hello') #send的效果和next一样 print('***',ret) #send 获取下一个值的效果和next基本一致 #只是在获取下一个值的时候,给上一yield的位置传递一个数据 #使用send的注意事项 # 第一次使用生成器的时候 是用next获取下一个值 # 最后一个yield不能接受外部的值
def func1(): print(11) print(333) yield 222 print(666) yield 777 g_obj = func1() # 生成器对象 generator object , 生成器对象不能直接打印,生成器本质也是迭代器,需要使用.__next__ 读取到yield print(g_obj.__next__()) print(g_obj.__next__())
列表推导式和生成器表达式
列表推导式 简单明了,但是占内存
生成器表达式 节省内存,不易看出。
1.把列表解析的[]换成()得到的就是生成器表达式
2.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存
3.Python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。例如, sum函数是Python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可以直接这样计算一系列值的和:
sum(x ** 2 for x in range(4))
列表推导式
列表推导式:能用列表推导式完成的,用python代码都可以完成。
用一句话构建一个你想要的列表。
优点:简单,稍微难理解。
缺点: 不能用debug。
[ 变量(加工后的变量) for 变量 in 可迭代对象 ] 遍历模式
li = [i for i in range(1, 12)] print(li)
[ 变量(加工后的变量) for 变量 in 可迭代对象 if 判断] 筛选模式
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'], ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] l3 = [ name for i in names for name in i if name.count('e') == 2] print(l3)字典
字典推导式
例一:将一个字典的key和value对调
mcase = {'a': 10, 'b': 34} mcase_frequency = {mcase[k]: k for k in mcase} print(mcase_frequency)
例二:合并大小写对应的value值,将k统一成小写
mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3} mcase_frequency = {k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0) for k in mcase.keys()} print(mcase_frequency)
集合推导式
计算列表中每个值的平方,自带去重功能
squared = {x**2 for x in [1, -1, 2]} print(squared) # Output: set([1, 4])
生成器表达式
把列表解析的[]换成()得到的就是生成器表达式
生成器对象不能直接打印,需要使用for循环配合 .__next__ 读取
g = (i*i for i in range(1, 11)) for i in g: print(i)