我开始学习Python,我遇到过生成器函数,其中有yield语句。我想知道这些函数最擅长解决什么类型的问题。
当前回答
请参阅PEP 255中的“动机”部分。
生成器的一个不太明显的用途是创建可中断函数,它允许您在不使用线程的情况下“同时”执行更新UI或运行多个作业(实际上是交错的)。
其他回答
缓冲。当以大块获取数据是有效的,但以小块处理数据时,生成器可能会有所帮助:
def bufferedFetch():
while True:
buffer = getBigChunkOfData()
# insert some code to break on 'end of data'
for i in buffer:
yield i
上面的方法可以让您轻松地将缓冲与处理分开。消费者函数现在可以一个一个地获取值,而不用担心缓冲。
我最喜欢的用法是“过滤”和“减少”操作。
假设我们正在读取一个文件,并且只想要以“##”开头的行。
def filter2sharps( aSequence ):
for l in aSequence:
if l.startswith("##"):
yield l
然后,我们可以在适当的循环中使用生成器函数
source= file( ... )
for line in filter2sharps( source.readlines() ):
print line
source.close()
reduce的例子类似。假设我们有一个文件,其中我们需要定位<Location>…< / >位置线。[不是HTML标签,而是恰好看起来像标签的行。]
def reduceLocation( aSequence ):
keep= False
block= None
for line in aSequence:
if line.startswith("</Location"):
block.append( line )
yield block
block= None
keep= False
elif line.startsWith("<Location"):
block= [ line ]
keep= True
elif keep:
block.append( line )
else:
pass
if block is not None:
yield block # A partial block, icky
同样,我们可以在一个合适的for循环中使用这个生成器。
source = file( ... )
for b in reduceLocation( source.readlines() ):
print b
source.close()
其思想是,生成器函数允许我们过滤或减少序列,每次生成一个值的另一个序列。
一堆东西。任何时候你想要生成一个项目序列,但又不想一次将它们全部“物化”到一个列表中。例如,你可以有一个简单的生成器,返回质数:
def primes():
primes_found = set()
primes_found.add(2)
yield 2
for i in itertools.count(1):
candidate = i * 2 + 1
if not all(candidate % prime for prime in primes_found):
primes_found.add(candidate)
yield candidate
然后你可以用它来生成后续质数的乘积:
def prime_products():
primeiter = primes()
prev = primeiter.next()
for prime in primeiter:
yield prime * prev
prev = prime
这些都是相当简单的示例,但是您可以看到它对于处理大型(可能是无限的!)数据集是多么有用,而无需预先生成数据集,这只是比较明显的用途之一。
使用生成器的原因之一是为了使某些解决方案的解决方案更清晰。
另一种方法是一次处理一个结果,避免建立庞大的结果列表,否则无论如何都要分开处理。
如果你有这样一个fibonacci- to-n函数:
# function version
def fibon(n):
a = b = 1
result = []
for i in xrange(n):
result.append(a)
a, b = b, a + b
return result
你可以更容易地写出这样的函数:
# generator version
def fibon(n):
a = b = 1
for i in xrange(n):
yield a
a, b = b, a + b
函数更清晰。如果你这样使用这个函数:
for x in fibon(1000000):
print x,
在本例中,如果使用生成器版本,则根本不会创建整个1000000项列表,每次只创建一个值。在使用列表版本时,情况并非如此,在列表版本中,将首先创建列表。
我发现生成器非常有助于清理代码,并为您提供了一种非常独特的方式来封装和模块化代码。如果您需要某些东西根据自己的内部处理不断地输出值,并且需要从代码中的任何地方调用该东西(而不仅仅是在循环或块中),则可以使用生成器。
一个抽象的例子是斐波那契数生成器,它不在循环中,当从任何地方调用它时,它总是返回序列中的下一个数字:
def fib():
first = 0
second = 1
yield first
yield second
while 1:
next = first + second
yield next
first = second
second = next
fibgen1 = fib()
fibgen2 = fib()
现在你有了两个斐波那契数生成器对象,你可以在代码中的任何地方调用它们,它们总是会按如下顺序返回更大的斐波那契数:
>>> fibgen1.next(); fibgen1.next(); fibgen1.next(); fibgen1.next()
0
1
1
2
>>> fibgen2.next(); fibgen2.next()
0
1
>>> fibgen1.next(); fibgen1.next()
3
5
生成器的可爱之处在于,它们封装了状态,而不必经历创建对象的繁琐过程。考虑它们的一种方法是将它们视为记住其内部状态的“函数”。
我从Python生成器中得到了斐波那契函数的例子——它们是什么?只要有一点想象力,您就可以想出很多其他情况,在这些情况下,生成器可以很好地替代for循环和其他传统迭代结构。
推荐文章
- 证书验证失败:无法获得本地颁发者证书
- 当使用pip3安装包时,“Python中的ssl模块不可用”
- 无法切换Python与pyenv
- Python if not == vs if !=
- 如何从scikit-learn决策树中提取决策规则?
- 为什么在Mac OS X v10.9 (Mavericks)的终端中apt-get功能不起作用?
- 将旋转的xtick标签与各自的xtick对齐
- 为什么元组可以包含可变项?
- 如何合并字典的字典?
- 如何创建类属性?
- 不区分大小写的“in”
- 在Python中获取迭代器中的元素个数
- 解析日期字符串并更改格式
- 使用try和。Python中的if
- 如何在Python中获得所有直接子目录