又称解析式。
推导式是可以从一 个数据序列构建另一个新的数据序列的结构体。
打印奇数
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
b = [x for x in a if x % 2 == 1]
c = [x ** 2 for x in a if x % 2 == 1]
print(b, c)
结果:
[1, 3, 5, 7, 9] [1, 9, 25, 49, 81]
打印30以内的所有能被3整除的数
print([i for i in range(1, 31) if i % 3 == 0])
嵌套循环
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva', 'Elven']]
print([name for lst in names for name in lst if name.count("e") == 2])
结果:
['Jefferson', 'Wesley', 'Steven', 'Jennifer']
过滤50以内能被3整除的数,如果这个数是奇数就返回0,偶数返回这个数本身
print([i if i % 2 == 0 else 0 for i in range(1, 51) if i % 3 == 0])
d1 = {"a": 1, "b": 2}
d2 = {v: k for k, v in d1.items()}
print(d2)
结果:
{1: 'a', 2: 'b'}
dic = {'a': 1, 'b': 2, 'c': 3, 'ab': 4}
li = {k: v for k, v in dic.items() if 'a' not in k}
print(li)
结果:
{'b': 2, 'c': 3}
和列表推导式一致,只是这里使用{},自带去重功能
l = [-1, 1, 1, 1, 2, 3]
print({i * i for i in l})
结果:
{1, 4, 9}
q1 = ['a', 'ab', 'abc', 'abcd', 'abcde']
print([i.upper() for i in q1 if len(i) >= 3])
x = [i for i in range(0, 6) if i % 2 == 0]
y = [i for i in range(0, 6) if i % 2 != 0]
print([(i, j) for i in x for j in y])
q3 = {'a': 10, 'b': 34}
print({v: k for k, v in q3.items()})
q4 = {'B': 3, 'a': 1, 'b': 6, 'c': 3, 'A': 4}
print({k.lower(): q4.get(k.lower(), 0) + q4.get(k.upper(), 0) for k in q4.keys()})
定义:凡是可以返回一个迭代器的对象都可称之为可迭代对象。
判断:
分类:容器类型、打开状态的files,sockets、range
迭代器: 实现了__iter__ 和__next__ 的方法的都叫做迭代器
__iter__返回自身
__next__返回下一个值
for语法糖:先调用可迭代对象的__iter__ 方法,返回一个迭代器,然后再对迭代器调用__next__ 方法,知道最后一个退出
迭代器可以没有__iter__方法,但是要是for循环的话就要有__iter__方法,返回自身
lst = ['x', 'y', 1, 3, 4]
result = lst.__iter__() #调用__iter__()方法 返回迭代器
print(result.__next__()) #迭代器调用__next__()方法不断获取下一个值
print(result.__next__()) #超出范围就会报错
**懒加载:**需要的时候再生成,而列表一次性生成保存在内存中
from collections.abc import Iterable, Iterator
range_iter = iter(range(10))
print(isinstance(range_iter, Iterable)) # 判断是否是可迭代对象
print(isinstance(range_iter, Iterator)) # 判断是否是迭代器
好处:迭代器就像一个懒加载的工厂惰性求值,等到有人需要的时候才给它生成值返回,没调用的时候就处于休眠状态等待下一次调用
from itertools import count
c = count(start=10) # 指定从10开始,步长默认为1
c = count(10, 2) # 从10开始,步长为2 ,调用next可以生成无限序列
print(c, type(c))
print(next(c))
print(next(c))
print(next(c))
count(10, 2) <class 'itertools.count'>
10
12
14
from itertools import cycle
import time
weeks = cycle(["Mon","Tue","Wed","Thu","Fri","Sat","Sun"])
print(weeks,type(weeks))
for i in weeks:
print(i)
time.sleep(1)
生成器一定是迭代器。懒加载,是迭代器更优雅的写法
不需要手动实现iter、next方法
生成器只有俩种写法:生成器表达式、生成器函数
类似于列表推导式,使用()生成generator。没有手动实现__iter__和__next__方法
result = (x for x in range(1,31) if x % 3 == 0)
print(result,type(result))
结果:
<generator object <genexpr> at 0x000002F156454580>
<class 'generator'>
包含了yield关键字的函数
把普通函数变成生成器
作用:
• 当生成器遇到一个yield时,会暂停运行生成器,返回yield后面的值。
• 当再次调用生成器的时候,会从刚才暂停的地方继续运行,直到下一个yield。
• yield关键字:保留中间算法,下次继续执行
def get_content():
x = 2
yield x
y = 3
yield y
z = 4
yield z
g = get_content()
print(g, dir(g))
print(next(g)) # 第一次执行next函数的时候 遇到yeild就退出,并且返回yeild后面携带的参数,还会记录位置
print(next(g))# 第二次执行的时候就会从上一次执行的地方继续执行
print(next(g))
def func1():
count = 1
while 1:
yield count
count += 1
f = func1()
print(next(f))
print(next(f))
写法一:
num = input("请输入数列长度:")
def func1():
a = 1
yield a
b = 1
yield b
while 1:
tmp = a + b
yield tmp
a = b
b = tmp
f = func1()
for i in range(int(num)):
print(next(f), end=" ")
写法二:
num = input("请输入数列长度:")
def func1():
a = 0
b = 1
while 1:
yield b
a, b = b, a+b
f = func1()
for i in range(int(num)):
print(next(f), end=" ")
当你需要以迭代的方式去处理一个巨大的数据集合。比如:一个巨大的文件/一个复杂的数据库查 询等。
• 可以用更少地中间变量写流式代码
• 相比其它容器对象它更能节省内存
• 可以用更少的代码来实现相似的功能
def read_file(fpath):
BLOCK_SIZE = 1024
with open(fpath, "rb") as f:
while True:
block = f.read(BLOCK_SIZE)
if block:
yield block
else:
return
如果直接对文件对象调用 read() 方法,会导致不可预测的内存占用。好的方法是利用固定长度的 缓冲区来不断读取文件的部分内容。通过 yield,我们不再需要编写读文件的迭代类,就可以轻松 实现文件读取。
def counter(start_at=0):
count = start_at
while True:
val = (yield count)# send 发送一个数据会赋值给val,next获取时,val为None
if val is not None:
count = val
else:
count += 1
count = counter(5)
print(type(count))
print(count.__next__())
print(count.send(9))
print(count.__next__())
count.close() # 关闭生成器,后就不能调用next()
print(count.__next__())
后面必须返回可迭代对象
def g1(x):
yield range(x)
def g2(x):
yield from range(x)
it1 = g1(5) #生成器1
it2 = g2(5) #生成器2
print([x for x in it1])
print([x for x in it2])
结果:
[range(0, 5)]
[0, 1, 2, 3, 4]
可迭代对象iterable
迭代器 iterator
生成器 generator
如何判断一个对象是可迭代对象,迭代器对象或生成器 ?
实现了iter方法的就是可迭代对象,同时实现了next方法的就是迭代器对象。
包含了yeild关键字的迭代器就是生成器
迭代器与生成器的区别 ?
生成器能做到迭代器能做的所有事,而且因为自动创建了 iter()和 next()方法,生成器显得特别简洁
生成器也是高效的,使用生成器表达式取代列表解析可以同时节省内存。除了创建和保存程序状态的自动方法,当生成器终结时,还会自动抛出 StopIteration 异常。
生成器也是一种迭代器,但是只能迭代一次,因为只保存一次值
可迭代对象与迭代器的区别?
实现了iter方法的就是可迭代对象,同时实现了next方法的就是迭代器对象。
如何定义一个生成器 ?
类似于列表推导式,使用()生成generator。
定义包含yield关键字的函数
如何获取可迭代对象、迭代器与生成器中的数据?
可迭代对象 :for循环
迭代器、生成器:调用__next__()方法