请参考:
https://docs.python.org/3.6/tutorial/index.html
https://docs.python.org/3.6/reference/
Iterable,Iterator,Generator,list 之间的关系
1 list
尽量使用 python 的列表推导特性。
list(range(5))
# [0, 1, 2, 3, 4]
[i for i in range(10) if i % 2 == 0]
# [0, 2, 4, 6, 8]
['%d:%s' % (i, v) for i, v in enumerate(['one', 'two', 'three'])]
# ['0:one', '1:two', '2:three']
knights = {'gallahad': 'the pure', 'robin': 'the brave'}
["%s: %s" % (k,v) for k,v in knights.items()]
# ['gallahad: the pure', 'robin: the brave']
["%s: %s" % (k,v) for k,v in zip([1,2,3], ["one", "two", "three"])]
# ['1: one', '2: two', '3: three']
- enumerate 产生一个能返回(索引,值)的迭代器!
- zip 能将两个 list 中的值组合成一个 pair
2 Iterator
在 Python 中,可以直接进行 for 循环的数据类型有以下几种:
- list, tuple, dict, set, str
- generator, 包括生成器和带 yield 的 generator function
这些对象都统称为可迭代对象:Iterable
Iterable 对象不一定是迭代器 Iterator,因为迭代器不但可以进行 for 循环,还可以被 next() 函数调用并返回下一个迭代值,直到抛出 StopIteration 异常。
from collections import Iterable, Iterator
isinstance('abc', Iterable) # True
isinstance('abc', Iterator) # False
可以通过 iter 内建函数将 Iterable 对象转变为 Iterator
i = iter('123')
isinstance(i, Iterator) # True
next(i) # 1
next(i) # 2
next(i) # 3
next(i) # 产生 StopIteration 异常
自定义 Iterator 方法 1: 通过编写一个具有next方法的类
class MyIter(object):
def __init__(self, num):
self.num = num
def __next__(self):
if self.num == 0:
raise StopIteration
self.num -= 1
return self.num
def __iter__(self):
return self
[i for i in MyIter(4)] # [3, 2, 1, 0]
自定义 Iterator 方法 2: 使用生成器
def myiter(num):
while num > 0:
num -= 1
yield num
[i for i in myiter(4)] # [3, 2, 1, 0]
通过 next() 访问 Iterator 太麻烦了,一般通过 for … in 的形式来遍历它。
# next
try:
while True:
value = next(gen)
process(value)
except StopIteration:
break
# for ... in
for value in gen:
process(value)
3 Generator
生成器可以更简洁、有效的生成迭代器。
通过 () 创建生成器
a = (i*i for i in range(4))
type(a) # generator object
next(a) # 0
next(a) # 1
next(a) # 4
next(a) # 9
next(a) # StopIteration
通过 yield 创建生成器:
def foo():
yield 3
a = foo()
type(a) # generator
# 斐波拉切数列
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a+b
n += 1
return 'done'
[i for i in fib(5)] # [1,1,2,3,5]
除了通过 next 方法实现迭代器,还可以通过 send 方法来获取输入。
def mg():
print("first line")
while True:
vin = yield
print("loop %s "% vin)
m = mg()
m.send(None) # first line : start generator
m.send("1") # loop 1
m.send("2") # loop 2
a = mg()
next(a)
a.send(2) # loop 2
send 可以看做能够传参的 next
def demo(num):
print("Start")
while num > 0:
vin = yield num
print("loop: %s" % vin)
num -= 1
d = demo(3)
r = d.send(None) # r == 3
r = d.send(4) # r == 2, loop: 4
可以得出以下关系:
yin = yield yout
sout = x.send(sin)
yin == sin # True
yout == sout # True