python--迭代器与生成器;列表推导式,生成器表达式,各种推导式
一,迭代器
1.1什么是可迭代对象?
(字符串、列表、元组、字典、集合都可以被for循环,说明他们都是可迭代的。)
什么是可迭代对象:内部含有__iter__方法的对象就叫做可迭代对象
可迭代对象就遵循可迭代协议。
1.2判断迭代对象的两种方法:
第一种:print("__iter__" in dir(object)) dic() 查看数据类型的所有方法。
第二种:from collections import Iterable
print(isinstance(objcet,Iterable)) #返回True 就是
或者
from collections import Iterator
print(isinstance(objcet,Iterator))
1.3迭代器
将可迭代对象转化成迭代器:可迭代对象.__iter__()
1,将可迭代对象转化成迭代器
2,内部使用__next__方法取值
3,运用了异常处理去处理报错。
1.4迭代器的属性
迭代器不仅含有__iter__,还包含__next__。遵循迭代器协议。
判断迭代器的方法:
print('__iter__' in dir(l1_obj))
print('__next__' in dir(l1_obj))
from collections import Iterator
print(isinstance(l1_obj, Iterator))
while循环模拟for循环的机制。
li = [4,5,6,7,43,3,2] li_obj = li.__iter__() while True: try: m = li_obj.__next__() print(m) except Exception: break
1.5迭代器的好处:
1.节省内存空间
2.满足惰性机制
3.不能反复取值,不可逆。
二,生成器Generator
2.1初始生成器
一个包含yield关键字的函数就是一个生成器函数。yield可以为我们从函数中返回值,但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象。每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。
我们知道的迭代器有两种:一种是调用方法直接返回的,一种是可迭代对象通过执行iter方法得到的,迭代器有的好处是可以节省内存。
如果在某些情况下,我们也需要节省内存,就只能自己写。我们自己写的这个能实现迭代器功能的东西就叫生成器。
生成器Generator:
本质:迭代器(所以自带了__iter__方法和__next__方法,不需要我们去实现)
特点:惰性运算,开发者自定义
2.2生成器的产生方式
1,生成器函数构造。
2,生成器推导式构造。
2.3函数构造,生成器
def func():
print(111)
print(222)
print(333)
yield 666
yield 555
yield 777
g = func()
第一:函数中只要有yield 那他就不是一个函数,而是一个生成器
第二:g称作生成器对象。
2.4关键字 send
send 获取下一个值的效果和next基本一致
只是在获取下一个值的时候,给上一yield的位置传递一个数据
使用send的注意事项
第一次使用生成器的时候 是用next获取下一个值
最后一个yield不能接受外部的值
from functools import wraps def init(func): #在调用被装饰生成器函数的时候首先用next激活生成器 @wraps(func) def inner(*args,**kwargs): g = func(*args,**kwargs) next(g) return g return inner @init def averager(): ''' 这是一个计算平均移动速度的函数 :return: 移动速度值 ''' total = 0.0 count = 0 average = None while True: term = yield average total += term count += 1 average = total/count g_avg = averager() # next(g_avg) 在装饰器中执行了next方法 print(g_avg.send(10)) print(g_avg.send(30)) print(g_avg.send(5)) print(averager.__doc__) print(averager.__name__)
def gen1(): for c in 'AB': yield c for i in range(3): yield i print(list(gen1())) def gen2(): yield from 'AB' yield from range(3) print(list(gen2()))
面试题一: 一个生成器只能取一次值 def demo(): # 1- 定义生成器函数demo for i in range(4): yield i g=demo() # 2- 调用demo函数,不会执行这个函数中的代码,只会获得一个生成器(迭代器) g1=(i for i in g) # 3- 本质是利用生成器表达式创建生成器函数,不会执行这个函数中的代码,只会获得一个生成器(迭代器) g2=(i for i in g1) # 4- 本质是利用生成器表达式创建生成器函数,不会执行这个函数中的代码,只会获得一个生成器(迭代器) print(list(g1)) # 5- 开始取值,向g1要值,g1是一个生成器,g1向g要值,g也是一个生成器,g向demo要值,demo会给g1 -- 0,1,2,3 print(list(g2)) # 6- g2是一个生成器,向g1要值,g1向g要值,g也是一个生成器,g向demo要值,此时demo中的值已经被取完了 # [0, 1, 2, 3] # []
# 面试题二 生成器在不找它要值的时候始终不执行 # 当它执行的时候,要以执行时候的所有变量值为准 def add(n,i): return n+i def test(): for i in range(4): yield i g=test() for n in [1,10]: g=(add(n,i) for i in g) print(list(g)) ------------------------------------------------- # 将for循环转化为非循环代码 # for n in [1,10]: # g=(add(n,i) for i in g) # 转化为 # n = 1 # g=(add(n,i) for i in g) # n = 10 # g=(add(n,i) for i in g) # 因为生成器表达式只是创建生成器函数,***不会执行这个函数中的代码*** # 只会获得一个生成器(迭代器)g,这个g就是n=10的时候括号里for循环中的g # 所以list(g)中的g为n=10的时候的值,下面是推导过程 n = 10 # g=(add(n,i) for i in g) # g=(add(n,i) for i in (add(n,i) for i in test())) # g=(add(n,i) for i in (add(n,i) for i in [0,1,2,3])) # g=(add(10,i) for i in (add(10,i) for i in [0,1,2,3])) # g=(add(10,i) for i in (10,11,12,13)) g=(20,21,22,23) print(list(g)) # [20, 21, 22, 23]
三、列表推导式
1.li = [i for i in range(1,101)]
print(li)
2.
multiples = [i for i in range(30) if i % 3 is 0] #可加判断条件
print(multiples)
3.
li = [i for i in range(1,10)]升级:前面的i可以添加三元运算:
li = [i if i < 5 else i*i for i in range(10)]
4.
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'], ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] print([name for lst in names for name in lst if name.count('e') >= 2]) # 注意遍历顺序,这是实现的关键
5.将一个字典的key和value对调 字典生成式

1.把列表解析的[]换成()得到的就是生成器表达式
2.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存
根据value值来排序字典的keys
>>> d = {'a': 7, 'c': 4, 'b': 3, 'd': 4, 'f': 6, 'e': 1}
>>> t = sorted([(v, k) for k, v in d.items()])
>>> print([k for v, k in t])
['e', 'b', 'c', 'd', 'f', 'a']
四、生成器表达式
li = [i for i in rang(1,101)]将列表推导式外面的[]变成(),就是一个生成器表达式。
li = (i for i in rang(1,101))
五、各种推导式
1、列表推导式
例一:30以内所有能被3整除的数
multiples = [i for i in range(30) if i % 3 is 0]
print(multiples)
# Output: [0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
例二:30以内所有能被3整除的数的平方
def squared(x):
return x*x
multiples = [squared(i) for i in range(30) if i % 3 is 0]
print(multiples)
例三:找到嵌套列表中名字含有两个‘e’的所有名字
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
print([name for lst in names for name in lst if name.count('e') >= 2]) # 注意遍历顺序,这是实现的关键
2、字典推导式
例一:将一个字典的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)
mcase.get(k.lower(), 0) # 0是默认值,如果对应的key没有vlues就用0
3、集合推导式
例:计算列表中每个值的平方,自带去重功能
squared = {x**2 for x in [1, -1, 2]}
print(squared)
# Output: set([1, 4])
练习题:
例1: 过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母
例2: 求(x,y)其中x是0-5之间的偶数,y是0-5之间的奇数组成的元祖列表
例3: 求M中3,6,9组成的列表M = [[1,2,3],[4,5,6],[7,8,9]]
1.[name.upper() for name in names if len(name)>3] 2.[(x,y) for x in range(5) if x%2==0 for y in range(5) if y %2==1] 3. [row[2] for row in M]

浙公网安备 33010602011771号