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)