【Python】笔记:可迭代的对象、迭代器和生成器

可迭代的对象、迭代器和生成器

import re
import reprlib

RE_WORD = re.compile('\w+')

class Sentence_v1:

    def __init__(self, text):
        self.text = text
        self.words = RE_WORD.findall(text)

    def __getitem__(self, index):
        return self.words[index]
    
    def __len__(self):
        return len(self.words)
    
    def __repr__(self):
        return 'Sentence(%s)' % reprlib.repr(self.text)
s = Sentence_v1('"The time has come," the Walrus said,')
print(repr(s))
for word in s:
    print(word)
Sentence('"The time ha... Walrus said,')
The
time
has
come
the
Walrus
said

当解释器需要迭代对象时,

  1. __iter__
  2. __getitem__
  3. 抛出 TypeError
class Foo:
    def __iter__(self):
        pass

from collections import abc
print(issubclass(Foo, abc.Iterable))
f = Foo()
print(isinstance(f, abc.Iterable))
True
True
s = 'ABC'
for char in s:
    print(char)
A
B
C
s = 'ABC'
it = iter(s)
while True:
    try:
        print(next(it))
    except StopIteration:
        del it
        break
A
B
C
import re
import reprlib

RE_WORD = re.compile('\w+')

class Sentence_v2:

    def __init__(self, text):
        self.text = text
        self.words = RE_WORD.findall(text)
    
    def __repr__(self):
        return 'Sentence(%s)' % reprlib.repr(self.text)

    def __iter__(self):
        return SentenceIterator(self.words)

class SentenceIterator:
    
    def __init__(self, words):
        self.words = words
        self.index = 0

    def __next__(self):
        try:
            word = self.words[self.index]
        except IndexError:
            raise StopIteration()
        self.index += 1
        return word
    
    def __iter__(self):
        return self

__iter__ 实例化并返回一个迭代器

import re
import reprlib

RE_WORD = re.compile('\w+')

class Sentence_v3:

    def __init__(self, text):
        self.text = text
        self.words = RE_WORD.findall(text)
    
    def __repr__(self):
        return 'Sentence(%s)' % reprlib.repr(self.text)

    def __iter__(self):
        for word in self.words:
            yield word
        return  # 可有可无

yield

惰性求值

# yield

def gen_AB():
    print('start')
    yield 'A'
    print('continue')
    yield 'B'
    print('end')  # 第三次迭代到这里后, 抛出异常, 被 for 捕捉, 停止迭代

for c in gen_AB():
    print('--> ', c)
start
-->  A
continue
-->  B
end
import re
import reprlib

RE_WORD = re.compile('\w+')

class Sentence_v4:

    def __init__(self, text):
        self.text = text
    
    def __repr__(self):
        return 'Sentence(%s)' % reprlib.repr(self.text)

    def __iter__(self):
        for match in RE_WORD.finditer(self.text):
            yield match.group()

惰性求值与迫切求值

l1 = [x for x in gen_AB()]
start
continue
end
for x in l1:
    print(x)
A
B
g1 = (x for x in gen_AB())
for x in g1:
    print(x)
start
A
continue
B
end
import re
import reprlib

RE_WORD = re.compile('\w+')

class Sentence_v5:

    def __init__(self, text):
        self.text = text
    
    def __repr__(self):
        return 'Sentence(%s)' % reprlib.repr(self.text)

    def __iter__(self):  # 直接返回一个 iter
        return (match.group() for match in RE_WORD.finditer(self.text))

无限等差数列

class ArithmeticProgression:

    def __init__(self, begin, step, end=None):
        self.begin, self.step, self.end = begin, step, end

    def __iter__(self):
        result = type(self.begin + self.step)(self.begin)  将 
        forever = self.end is None

        index = 0
        while forever or result < self.end:
            yield result
            index += 1
            result = self.begin + self.step * index
def aritprog_gen(begin, step, end=None):
    result = type(begin + step)(begin)
    forever = end is None
    index = 0
    while forever or result < end:
            yield result
            index += 1
            result = begin + step * index

itertools 中的 等差数列

import itertools
gen = itertools.count(1, .5)
print(next(gen))
print(next(gen))
print(next(gen))
1
1.5
2.0

itertools.takewhile 生成一个使用另一个生成器的生成器, 仅在计算结果为 False 时停止

gen2 = itertools.takewhile(lambda n: n < 3, itertools.count(1, .5))
print(list(gen2))
[1, 1.5, 2.0, 2.5]
def aritprog_gen2(begin, step, end=None):
    first = type(begin + step)(begin)
    ap_gen = itertools.count(first, step)
    if end is not None:
        ap_gen = itertools.takewhile(lambda n: n < end, ap_gen)
    return ap_gen

标准库中的生成器

用于过滤的生成器函数

模块 函数 说明
itertools compress(it, selector_it) 并行处理两个 iter , 如果 selector_it 中元素为真, 则产出对应 it 中的元素
itertools dropwhile(predicate, it) 处理 it , 跳过 predicate 中计算结果为真的元素, 然后查出剩下的各个元素(不再进一步检查)
(inner) filter(predicate, it) 把 it 中的各个元素传给 predicate, 如果 predicate(item) 返回真, 那么产出对应元素
itertools filterfalse(predicate, it) 与上面相反
itertools islice(it, stop)islice(it, start, stop, step=1) 产出 it 切片, 作用类似于 s[:stop] 或 s[start:stop:step], 但返回的是一个可迭代对象
itertools takewhile(predicate, it) predicate 返回真值时产出对应的元素, 然后立即停止, 不在继续检查
from itertools import filterfalse, dropwhile, takewhile, compress, islice

def vowel(c):
    return c.lower() in 'aeiou'

print('filter: ', list(filter(vowel, 'Aardvark')))  # 产出所有 aeiou
print('filterfalse: ', list(filterfalse(vowel, 'Aardvark')))  # 产出所有 除了aeiou

print('dropwhile: ', list(dropwhile(vowel, 'Aardvark')))  # 从第一个不是 aeiou 的元素开始产出到末尾
print('takewhile: ', list(takewhile(vowel, 'Aardvark')))  # 从第一个元素开始产出 到不是 aeiou 的元素停止

print('compress: ', list(compress('Aardvark', (1, 0, 1, 1, 0, 1))))  #  产出 后面 it 为真的元素

print('islice: ', list(islice('Aardvark', 1, 7, 2)))  # 类似于切片
filter:  ['A', 'a', 'a']
filterfalse:  ['r', 'd', 'v', 'r', 'k']
dropwhile:  ['r', 'd', 'v', 'a', 'r', 'k']
takewhile:  ['A', 'a']
compress:  ['A', 'r', 'd', 'a']
islice:  ['a', 'd', 'a']

用于映射的生成器函数

模块 函数 说明
itertools accumulate(it, func=sum) 每次将前两个元素传给 func, 产出计算结果, 默认 func=sum
(inner) enumerate(iterable, start=0) 每次产出(index, item), index 从 start 开始, 默认为 0
(inner) map(func, it1, it2, it3 ...) 把 it 中的各个元素传给 func, 产出结果, 多个 it 时, 并行处理, func(it1, it2, it3 ...), 遍历次数取最小 it
itertools starmap(func, it) 把 it 中各个元素传给 func, 产出结果, 输入的 it 应产出 可迭代对象 iit, 以 func(*iit) 的形式调用 func
from itertools import accumulate, starmap
from operator import mul

sample = [5, 4, 2, 8, 7, 6, 3, 0, 9, 1]

print('accumulate sum(default): ', list(accumulate(sample)))
print('accumulate min: ', list(accumulate(sample, min)))
print('accumulate max: ', list(accumulate(sample, max)))
print('accumulate mul: ', list(accumulate(sample, mul)))

print('accumulate fact: ', list(accumulate(range(1, 11), mul)))
accumulate sum(default):  [5, 9, 11, 19, 26, 32, 35, 35, 44, 45]
accumulate min:  [5, 4, 2, 2, 2, 2, 2, 0, 0, 0]
accumulate max:  [5, 5, 5, 8, 8, 8, 8, 8, 9, 9]
accumulate mul:  [5, 20, 40, 320, 2240, 13440, 40320, 0, 0, 0]
accumulate fact:  [1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800]
print('enumerate: ', list(enumerate('Ryugu Reina', 1)))

print('map', list(map(mul, range(11), range(11))))
print('map', list(map(mul, range(11), range(3))))  # 取最小长度

print('starmap', list(starmap(mul, enumerate('Ryugu Reina', 1))))
print('starmap', list(starmap(lambda a, b: b / a, enumerate(accumulate(sample), 1))))

enumerate:  [(1, 'R'), (2, 'y'), (3, 'u'), (4, 'g'), (5, 'u'), (6, ' '), (7, 'R'), (8, 'e'), (9, 'i'), (10, 'n'), (11, 'a')]
map [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
map [0, 1, 4]
starmap ['R', 'yy', 'uuu', 'gggg', 'uuuuu', '      ', 'RRRRRRR', 'eeeeeeee', 'iiiiiiiii', 'nnnnnnnnnn', 'aaaaaaaaaaa']
starmap [5.0, 4.5, 3.6666666666666665, 4.75, 5.2, 5.333333333333333, 5.0, 4.375, 4.888888888888889, 4.5]

合并多个可迭代对象的生成器

模块 函数 说明
itertools chain(it1, it2, ...) 将各个 it 拼接在一起
itertools chain.from_iterable(it1) 将各个 it 产出的 iit 拼接在一起
itertools product(it1, it2, ..., repeat=1) 计算笛卡尔积, repeat 重复处理多少次
(inner) zip(it1, it2, ...) 将各个 it 中的元素并行组成元组
itertools zip_longest(it1, it2, ..., fillvalue=None) 同上, 短的 it 用 fillvalue 填充
from itertools import chain, zip_longest, product
print('chain: ', list(chain('abc', range(2))))
print('chain.from_iterable:', list(chain.from_iterable(enumerate('abc'))))

print('zip: ', list(zip('abc', range(10))))
print('zip_longest: ', list(zip_longest('abc', range(10), fillvalue='q')))
chain:  ['a', 'b', 'c', 0, 1]
chain.from_iterable: [0, 'a', 1, 'b', 2, 'c']
zip:  [('a', 0), ('b', 1), ('c', 2)]
zip_longest:  [('a', 0), ('b', 1), ('c', 2), ('q', 3), ('q', 4), ('q', 5), ('q', 6), ('q', 7), ('q', 8), ('q', 9)]
print('product', list(product('ABC', range(2))))

suits = 'spades hearts diamonds clubs'.split()
print('product', list(product('AK', suits)))

print('product', list(product('ABC')))
print('product', list(product('AB', repeat=3)))  #<==> ('AB', 'AB', 'AB')
product [('A', 0), ('A', 1), ('B', 0), ('B', 1), ('C', 0), ('C', 1)]
product [('A', 'spades'), ('A', 'hearts'), ('A', 'diamonds'), ('A', 'clubs'), ('K', 'spades'), ('K', 'hearts'), ('K', 'diamonds'), ('K', 'clubs')]
product [('A',), ('B',), ('C',)]
product [('A', 'A', 'A'), ('A', 'A', 'B'), ('A', 'B', 'A'), ('A', 'B', 'B'), ('B', 'A', 'A'), ('B', 'A', 'B'), ('B', 'B', 'A'), ('B', 'B', 'B')]

把输入的各个元素扩展成多个输出元素的生成器

模块 函数 说明
itertools combinations(it, out_len) 把 it 产出的 out_len 个元素组合在一起, 然后产出, 即 out_len 个元素的组合
itertools combinations_with_replacement(it, out_len) 把 it 产出的 out_len 个元素组合在一起, 然后产出, 包含相同元素的组合
itertools count(start=0, step=1) 从 start 开始产出数字, 步长为 step
itertools rpcle(it, out_len) 把 it 产出的元素存储, 不断重复产出
itertools permutations(it, out_len=len(list(it))) 把 out_len 个产出的元素排列在一起, 然后产出这些排列, 即 out_len 个元素的排列
itertools repeat(item, [times]) 重复产出 item, 除非提供 times
from itertools import count, cycle, repeat, combinations, combinations_with_replacement, permutations, islice

ct = count()
print('count: ', next(ct), next(ct), next(ct))

print('count & islice: ', list(islice(count(1, .3), 3)))

cy = cycle('RUA')
print('cycle: ', next(cy), next(cy), next(cy), next(cy), next(cy), next(cy))

rp = repeat(6)
print('repeat: ', next(rp), next(rp), next(rp))

print('repeat: ', list(repeat(8, 4)))

print('repeat: ', list(map(mul, range(11), repeat(5))))

print('combinations', list(combinations('ABC', 2)))
print('combinations', list(combinations_with_replacement('ABC', 2)))
print('combinations', list(combinations('ABC', 1)))

print('permutations', list(permutations('ABC', 2)))
count:  0 1 2
count & islice:  [1, 1.3, 1.6]
cycle:  R U A R U A
repeat:  6 6 6
repeat:  [8, 8, 8, 8]
repeat:  [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]
combinations [('A', 'B'), ('A', 'C'), ('B', 'C')]
combinations [('A', 'A'), ('A', 'B'), ('A', 'C'), ('B', 'B'), ('B', 'C'), ('C', 'C')]
combinations [('A',), ('B',), ('C',)]
permutations [('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'C'), ('C', 'A'), ('C', 'B')]

用于重新排列的元素生成器

模块 函数 说明
itertools groupby(it, key=None) 产出由两个元素组成的元素 (key, group)
(inner) reversed(seq) 倒序产出 seq 中的元素, seq 必须是序列, 或者实现了 __reversed__
itertools tee(it, n=2) 产出由 n 个元素组成的元组
from itertools import groupby, tee

print(list(groupby('LLLLLLLAAAAAAGGGGGGGGGGGGGGGGGGGGGGGGG')))

for key, group in groupby('LLLLLLLAAAAAAGGGGGGGGGGGGGGGGGGGGGGGGG'):
    print(key, '-->', list(group))

print()
for key, group in groupby(['rua', 'aur', 'rau', 'aaaa', 'afeswr', 'sgse'], key=len):  # 按长度分组, 最好先排个序 -_-|
    print(key, '-->', list(group))

print()
for key, group in groupby(reversed(['rua', 'aur', 'rau', 'aaaa', 'afeswr', 'sgse']), key=len):  # 从右向左迭代列表
    print(key, '-->', list(group))

print()
g1, g2 = tee('ABC')  # 产出多个相同的迭代器
print('tee', next(g1), next(g2), next(g1))
[('L', <itertools._grouper object at 0x000001E3B5D93760>), ('A', <itertools._grouper object at 0x000001E3B5D93A30>), ('G', <itertools._grouper object at 0x000001E3B5D91390>)]
L --> ['L', 'L', 'L', 'L', 'L', 'L', 'L']
A --> ['A', 'A', 'A', 'A', 'A', 'A']
G --> ['G', 'G', 'G', 'G', 'G', 'G', 'G', 'G', 'G', 'G', 'G', 'G', 'G', 'G', 'G', 'G', 'G', 'G', 'G', 'G', 'G', 'G', 'G', 'G', 'G']

3 --> ['rua', 'aur', 'rau']
4 --> ['aaaa']
6 --> ['afeswr']
4 --> ['sgse']

4 --> ['sgse']
6 --> ['afeswr']
4 --> ['aaaa']
3 --> ['rau', 'aur', 'rua']

tee A A B

yield from

def chain_(*iterables):
    for it in iterables:
        for i in it:
            yield i

print(list(chain_('APPLE', range(3))))
['A', 'P', 'P', 'L', 'E', 0, 1, 2]
def chain_(*iterables):
    for it in iterables:
        yield from it

print(list(chain_('APPLE', range(3))))
['A', 'P', 'P', 'L', 'E', 0, 1, 2]

可迭代规约函数

模块 函数
(inner) all(it)
(inner) any(it)
(inner) max(it, [it2], ..., [key], [default])
(inner) min(it, [it2], ..., [key], [default])
functools reduce(func, it, [initial])
(inner) sum(it, start=0)

iter 函数

python 在迭代对象时会调用 iter(x)

iter(v, w) 其中, w 是哨符, 当生成器产出这个对象时, 会抛出 StopIteration, 停止迭代

from random import randint

def d6():
    return randint(1, 6)

d6_iter = iter(d6, 1)

for roll in d6_iter:  # 抛到 1 停止
    print(roll, end=' ')
3 6 2 4 
posted @ 2022-12-03 21:19  Zinc233  阅读(8)  评论(0编辑  收藏  举报