learn from 《流畅的python》
1. 迭代器
- 所有生成器都是迭代器,因为生成器完全实现了迭代器接口
- 序列可以迭代的原因:
iter 函数,解释器需要迭代对象 x 时,会自动调用 iter(x) - 内置的
iter :先检查是否实现了 __iter__ ,不然,检查是否实现 __getitem__ 并创建迭代器
标准的迭代器接口有两个方法
__next__ 返回下一个可用的元素,如果没有元素了,抛出 StopIteration 异常__iter__ 返回 self,以便在应该使用可迭代对象的地方使用迭代器,例如 在 for 循环中
不要在可迭代对象的类中实现迭代器,一举两得?错误,大佬教我不要这么做!
- 为了支持多种遍历,需要获取独立的多个迭代器,每次调用
iter() 都创建独立的迭代器对象
可迭代的对象 一定不能 是 自身的迭代器 也就是说,可迭代的对象 必须实现 __iter__ 方法,但不能实现 __next__ 方法
2. 生成器
只要 Python 函数的定义体中有 yield 关键字,该函数就是生成器函数 调用生成器函数时,会返回一个生成器对象
惰性获取匹配项 re.finditer ,可以节省内存和无效工作
生成器表达式可以理解为列表推导的惰性版本,按需 惰性生成元素
def genAB():
print("start")
yield 'A'
print("continue")
yield 'B'
print("end")
ans1 = [x*2 for x in genAB()]
for x in ans1:
print(x)
ans2 = (x*2 for x in genAB())
for x in ans2:
print(x)
3. 标准库
import itertools
gen = itertools.count(5, 0.5)
print(next(gen))
print(next(gen))
print(next(gen))
list(count()) 会生成无穷的序列,内存会爆炸
gen = itertools.takewhile(lambda n : n < 6, itertools.count(5, 0.5))
print(list(gen)) # [5, 5.5]
3.1 过滤
def vowel(c):
return c.lower() in "aeiou"
print(list(filter(vowel, "Abcdea")))
print(list(itertools.filterfalse(vowel, "Abcdea")))
print(list(itertools.dropwhile(vowel, "Aardvark")))
print(list(itertools.takewhile(vowel, "Aardvark")))
print(list(itertools.compress('Aardvark', (1, 0, 1, 1, 0, 1))))
print(list(itertools.islice('Aardvark', 4)))
print(list(itertools.islice('Aardvark', 4, 7)))
print(list(itertools.islice('Aardvark', 1, 7, 2)))
3.2 映射
sample = [9, 5, 4, 6, 8, 9]
print(list(itertools.accumulate(sample)))
print(list(itertools.accumulate(sample, min)))
print(list(itertools.accumulate(sample, max)))
print(list(itertools.accumulate(sample, operator.mul)))
print(list(itertools.accumulate(range(1, 11), operator.mul)))
print(list(enumerate("abc", start=2)))
print(list(map(operator.mul, range(11), range(1, 11))))
print(list(map(lambda a, b: (a, b), range(11), [2, 4, 8])))
print(list(itertools.starmap(operator.mul, enumerate('abc', 1))))
sample = [2, 3, 4, 5]
print(list(itertools.starmap(lambda a, b: b / a, enumerate(itertools.accumulate(sample), 1))))
3.3 合并
print(list(itertools.chain("ABC", range(5))))
print(list(itertools.chain(enumerate('ABC'))))
print(list(itertools.chain.from_iterable(enumerate('ABC'))))
print(list(zip('ABC', range(5))))
print(list(zip('ABC', range(5), [10, 20, 30, 40])))
print(list(itertools.zip_longest('ABC', range(5))))
print(list(itertools.zip_longest('ABC', range(5), fillvalue='?')))
print(list(itertools.product('ABC', range(2))))
print(list(itertools.product('ABC')))
print(list(itertools.product('ABC', repeat=2)))
print(list(itertools.product(range(2), repeat=3)))
rows = itertools.product('AB', range(2), repeat=2)
for row in rows: print(row)
print("-----")
for a in "AB":
for b in range(2):
for c in "AB":
for d in range(2):
print((a, b, c, d))
ct = itertools.count()
print(next(ct), next(ct), next(ct), next(ct), next(ct))
print(list(itertools.islice(itertools.count(1, .3), 3)))
cy = itertools.cycle('ABC')
print(next(cy), next(cy), next(cy), next(cy))
print(list(itertools.islice(cy, 7)))
rp = itertools.repeat(7)
print(list(itertools.islice(rp, 10)))
print(list(itertools.repeat(8, 4)))
print(list(map(operator.mul, range(11), itertools.repeat(5))))
3.4 排列组合
print(list(itertools.combinations("ABC", 2)))
print(list(itertools.combinations_with_replacement("ABC", 2)))
print(list(itertools.permutations("ABC", 2)))
print(list(itertools.product("ABC", repeat=2)))
3.5 重新排列
print(list(itertools.groupby("LLLLAAGGG")))
for char, group in itertools.groupby("LLLLAAGGG"):
print(char, "->", list(group))
for char, group in itertools.groupby("ALLLLAAGGG"):
print(char, "->", list(group))
animals = ['duck', 'eagle', 'rat', 'giraffe', 'bear', 'bat', 'dolphin', 'shark', 'lion']
animals.sort(key=len)
print(animals)
for length, group in itertools.groupby(animals, len):
print(length, "->", list(group))
for length, group in itertools.groupby(reversed(animals), len):
print(length, "->", list(group))
abc = ["apple", "bear", "animals", "bull", "lakers"]
abc.sort()
for char, group in itertools.groupby(abc, lambda x: x[0]):
print(char, "->", list(group))
print(list(itertools.tee("ABC")))
g1, g2 = itertools.tee("ABC")
print(next(g1))
print(list(g1))
print(next(g2), next(g2))
print(list(g2))
print(list(zip(*itertools.tee('ABC'))))
4. yield from
yield from 语句的作用就是把不同的生成器结合在一起使用
def chain(*iterables):
for it in iterables:
for i in it:
yield i
s = "ABC"
t = tuple(range(3))
print(list(chain(s, t)))
def chain1(*iterables):
for it in iterables:
yield from it
print(list(chain1(s, t)))
5. 可迭代的归约函数
any, all 可以短路,一旦确定结果,就停止迭代- 也可以这样调用
max(arg1, arg2, ..., [key=?]) sorted 操作完成后返回排序后的 列表。它可以处理任意的可迭代对象
print(all([1, 2, 3]))
print(all([0, 2, 3]))
print(all([]))
print(any([1, 2, 3]))
print(any([0, 2, 3]))
print(any([0, 0.0]))
print(any([]))
g = (n for n in [0, 0.0, 7, 8])
print(any(g))
print(list(g))
6. iter 还可以传入2个参数
def d6():
return random.randint(1, 6)
d6_iter = iter(d6, 1)
for roll in d6_iter:
print(roll)
print(list(d6_iter))
d6_iter = iter(d6, 1)
print(list(d6_iter))
这段代码逐行读取文件,直到遇到空行或者到达文件末尾为止
with open('mydata.txt') as fp:
for line in iter(fp.readline, '\n'):
process_line(line)
7. 生成器当成协程
.send() 方法,后面会学到- 与
.__next__() 方法一样,.send() 方法致使生成器前进到下一个 yield 语句 .send() 方法还允许使用生成器的客户 把 数据 发给 自己,即不管传给 .send() 方法什么参数,那个参数都会 成为生成器 函数定义体中对应的 yield 表达式的值
|