科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道应用软件深入了解Python暂缓列表生成器

深入了解Python暂缓列表生成器

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

上周我们向你介绍了python列表推导(list comprehension),它让你能以更加自然的方式来表示列表的内容。本文将介绍它们的同类:python生成器,它可以一段一段地构成一个序列,按照你的要求完成工作量。

作者:开发者在线 2007年7月20日

关键字:

  • 评论
  • 分享微博
  • 分享邮件

下面就让我们举一个真正派得上用场的例子。下面是一个相当标准的用于产生组合的函数,换句话说,一个序列可以以多种独特的方式被切割成小的序列:

def combination(seq, length):if not length: return [[]]else:l = []for i in xrange(len(seq)):for result in combination(seq[i+1:], length-1):l += [[seq[i]]+result]return l

它的用法是:

>>> combination("ABCDE", 3)
[['A', 'B', 'C'], ['A', 'B', 'D'], ['A', 'B', 'E'], ['A', 'C', 'D'], ['A', 'C', 'E'], ['A', 'D', 'E'], ['B', 'C', 'D'], ['B', 'C', 'E'], ['B', 'D', 'E'], ['C', 'D', 'E']]
>>> combination("ABCDE", 2)
[['A', 'B'], ['A', 'C'], ['A', 'D'], ['A', 'E'], ['B', 'C'], ['B', 'D'], ['B', 'E'], ['C', 'D'], ['C', 'E'], ['D', 'E']]
>>> combination("ABCDE", 5)
[['A', 'B', 'C', 'D', 'E']]

现在让我们改用生成器来做同样的事情。你想要在某些点往最终结果列表里加入一个值并用yield语句替换掉它,因此这里的技巧是简单地替换掉每一个这样的点。

def xcombination(seq,length):
if not length: yield []
else:
for i in xrange(len(seq)):
for result in xcombination(seq[i+1:], length-1):
yield [seq[i]]+result

现在我们用另一种方式获得了同样结果,唯一的不同是它只会按照你的需要来工作:

>>> comb = xcombination("ABCDE", 3)
>>> comb.next()
['A', 'B', 'C']
>>> comb.next()
['A', 'B', 'D']
>>> list(comb)
[['A', 'B', 'E'], ['A', 'C', 'D'], ['A', 'C', 'E'], ['A', 'D', 'E'], ['B', 'C', 'D'], ['B', 'C', 'E'], ['B', 'D', 'E'], ['C', 'D', 'E']]
>>> comb2 = xcombination("ABCDE",2)
>>> for i in xrange(3):
... print comb2.next()
... ['A', 'B']
['A', 'C']
['A', 'D']

在最后一条命令里,尽管有10种不同的字母组合,但是只生成了3个,与标准的函数相比,这就节省了70%的计算时间。

生成器真正的有用之处在于,在大多数情况下它们可以用作替代列表推导的放下(Drop)。你需要做的是用圆括号替换掉列表推导前后的方括号。我们就举《列表推导》一文中的最后一个例子。我们不需要:

>>> guests = ['Chris', 'Brendan', 'Jimmy', 'Mel', 'Mike', 'Jess']
>>> [(seat1, seat2) for seat1 in guests for seat2 in guests if seat1 != seat2]
...

你可以改用:

>>> guests = ['Chris', 'Brendan', 'Jimmy', 'Mel', 'Mike', 'Jess']
>>> ((seat1, seat2) for seat1 in guests for seat2 in guests if seat1 != seat2)

然后你可以像使用其他任何生成器一样使用它:

>>> seating = ((seat1, seat2) for seat1 in guests for seat2 in guests if seat1 != seat2)
>>> for i in xrange(10):
... print seating.next()
...
('Chris', 'Brendan')
('Chris', 'Jimmy')
('Chris', 'Mel')
('Chris', 'Mike')
('Chris', 'Jess')
('Brendan', 'Chris')
('Brendan', 'Jimmy')
('Brendan', 'Mel')
('Brendan', 'Mike')
('Brendan', 'Jess')

到现在我们已经在使用生成器了,在创建列表上它比其他方法节约计算时间。这非常好,但是它大展拳脚的地方是在不可能计算整个列表的时候。我们就以Fibonacci序列为例,在这个序列里,每个数字都是前面两个数字的和。假设我们想要一个能够生成到指定数字的序列:

>>> def fib(n):...a, b = 0, 1...l = [a]...while b < n:...l += [b]...a, b = b, a+b...return l... >>> fib(20)[0, 1, 1, 2, 3, 5, 8, 13]
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章