生成器

生成器表达式:迭代器遇到列表解析

从语法上来讲,生成器表达式就像一般的列表解析一样,但是它们是扩在圆括号中而不是方括号中。

从执行过程上来讲,生成器表达式很大不同:不是在内存中构建结果,而是返回一个生成器对象。

>>> G = (x ** 2 for x in range(4))
>>> next(G)
0
>>> next(G)
1
>>> next(G)
4
>>> next(G)
9
>>> next(G)
Traceback (most recent call last):
  File "<pyshell#38>", line 1, in <module>
    next(G)
StopIteration

在一个函数的基础上,编写一个列表解析基本上等同于:在一个list内置调用中包含一个生成器表达式迫使其一次生成列表中所有的结果。

>>> list((x ** 2 for x in range(4)))
[0, 1, 4, 9]

如果生成器表达式是在其他的括号之内,生成器自身的括号就不是必须的了。

>>> list((x ** 2 for x in range(4)))
[0, 1, 4, 9]
>>> sum(x ** 2 for x in range(4))
14
>>> sorted(x ** 2 for x in range(4))
[0, 1, 4, 9]
>>> sorted((x ** 2 for x in range(4)), reverse = True)
[9, 4, 1, 0]
>>> import math
>>> list(map(math.sqrt,(x ** 2 for x in range(4))))
[0.0, 1.0, 2.0, 3.0]

生成器是单迭代器对象

如果你手动地使用多个迭代器来迭代结果流,它们将会指向相同的位置:

>>> G = (c * 4 for c in 'SPAM')
>>> I1 = iter(G)
>>> next(I1)
'SSSS'
>>> next(I1)
'PPPP'
>>> I2 = iter(G)
>>> next(I2)
'AAAA'

 >>> next(G)
 'MMMM'

 

此外,一旦任何迭代器运行到完成,所有的迭代器都将用尽,必须产生一个新的生成器以再次开始。

编写自己的map(func, ...)

>>> def mymap(func, *seqs):
    res = []
    for args in zip(*seqs):
        res.append(func(*args))   #这个*很关键,没有的话无法运行。它收集多个序列参数,将其作为zip参数解包以便组合,然后成对的zip结果解包作为参数以便传入到函数。
    return res

>>> mymap(abs, [-2, -3, 0, 1, 2])
[2, 3, 0, 1, 2]
>>> mymap(pow, [1, 2, 3], [2, 3, 4])
[1, 8, 81]

 更精简的方式,作为单行列表解析的对等体:

>>> def mymap(func, *seqs):
    return [func(*args) for args in zip(*seqs)]

生成器函数和表达式重新编码这两种替代方案,使运行不浪费内存:

>>> def mymap(func, *seqs):
    res = []
    for args in zip(*seqs):
        yield func(*args)

>>> def mymap(func, *seqs):
    return (func(*args) for args in zip(*seqs))

模拟截断的zip:

def myzip(*seqs):
    seqs = [list(S) for S in seqs]
    res = []
    while all(seqs):
        res.append(tuple(S.pop(0) for S in seqs))
    return res

>>> S1, S2 = 'abc', 'xyz123'
>>> myzip(S1, S2)
[('a', 'x'), ('b', 'y'), ('c', 'z')

补充的map:

>>> def mymap(*seqs, pad = None):
    seqs = [list(S) for S in seqs]
    res = []
    while any(seqs):
        res.append(tuple((S.pop(0) if S else pad) for S in seqs))
    return res

>>> mymap(S1, S2)
[('a', 'x'), ('b', 'y'), ('c', 'z'), (None, '1'), (None, '2'), (None, '3')]
>>> mymap(S1, S2, pad = 99)
[('a', 'x'), ('b', 'y'), ('c', 'z'), (99, '1'), (99, '2'), (99, '3')]        

另一种方法,通过最大、最小参数来完成:

def myzip1(*seqs):
    minlen = min(len(S) for S in seqs)
    return [tuple(S[i] for S in seqs) for i in range(minlen)]

def mymapPad(*seqs, Pad = None):
    maxlen = max(len(S) for S in seqs)
    index = range(maxlen)
    return [tuple((S[i] if len(S)>i else Pad) for S in seqs) for i in range(index)]

 

更优的替代方法:

def myzip2(*args):
    iters = list[map(iter, args)]
    while iters:
        res = [next(i) for i in iters]
        yield tuple(res)
        

 


posted on 2018-04-06 23:00  11wayne  阅读(141)  评论(0)    收藏  举报

导航