我开始学习Python,我遇到过生成器函数,其中有yield语句。我想知道这些函数最擅长解决什么类型的问题。
当前回答
一堆东西。任何时候你想要生成一个项目序列,但又不想一次将它们全部“物化”到一个列表中。例如,你可以有一个简单的生成器,返回质数:
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
这些都是相当简单的示例,但是您可以看到它对于处理大型(可能是无限的!)数据集是多么有用,而无需预先生成数据集,这只是比较明显的用途之一。
其他回答
当我们的web服务器充当代理时,我使用生成器:
客户端从服务器请求一个代理url 服务器开始加载目标url 服务器在获得结果后立即将结果返回给客户机
简单的解释是: 考虑for语句
for item in iterable:
do_stuff()
很多时候,iterable中的所有项都不需要从一开始就存在,但可以在需要时动态生成。这在两种情况下都更有效
空间(您永远不需要同时存储所有项目)和 时间(迭代可能在需要所有项目之前完成)。
其他时候,你甚至不知道所有的项目提前。例如:
for command in user_input():
do_stuff_with(command)
你没有办法预先知道所有用户的命令,但如果你有一个生成器给你命令,你可以使用这样一个很好的循环:
def user_input():
while True:
wait_for_command()
cmd = get_command()
yield cmd
使用生成器,您还可以对无限序列进行迭代,这在迭代容器时当然是不可能的。
缓冲。当以大块获取数据是有效的,但以小块处理数据时,生成器可能会有所帮助:
def bufferedFetch():
while True:
buffer = getBigChunkOfData()
# insert some code to break on 'end of data'
for i in buffer:
yield i
上面的方法可以让您轻松地将缓冲与处理分开。消费者函数现在可以一个一个地获取值,而不用担心缓冲。
一堆东西。任何时候你想要生成一个项目序列,但又不想一次将它们全部“物化”到一个列表中。例如,你可以有一个简单的生成器,返回质数:
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
这些都是相当简单的示例,但是您可以看到它对于处理大型(可能是无限的!)数据集是多么有用,而无需预先生成数据集,这只是比较明显的用途之一。
由于没有提到生成器的send方法,这里有一个例子:
def test():
for i in xrange(5):
val = yield
print(val)
t = test()
# Proceed to 'yield' statement
next(t)
# Send value to yield
t.send(1)
t.send('2')
t.send([3])
它展示了向运行中的生成器发送值的可能性。下面视频中关于生成器的更高级课程(包括解释的yield,并行处理的生成器,逃避递归限制等)
David Beazley在PyCon 2014上谈发电机