我开始学习Python,我遇到过生成器函数,其中有yield语句。我想知道这些函数最擅长解决什么类型的问题。
当前回答
现实世界中的例子
假设你的MySQL表中有1亿个域名,你想为每个域名更新Alexa排名。
你需要做的第一件事是从数据库中选择域名。
假设表名为domains,列名为domain。
如果你使用SELECT domain FROM domains,它将返回1亿行,这将消耗大量内存。所以您的服务器可能会崩溃。
所以你决定分批运行这个程序。假设我们的批量大小是1000。
在我们的第一批中,我们将查询前1000行,检查每个域的Alexa排名并更新数据库行。
在我们的第二批中,我们将处理接下来的1000行。第三批将从2001年到3000年,以此类推。
现在我们需要一个生成器函数来生成我们的批。
这是我们的生成器函数:
def ResultGenerator(cursor, batchsize=1000):
while True:
results = cursor.fetchmany(batchsize)
if not results:
break
for result in results:
yield result
正如你所看到的,我们的函数总是得到结果。如果使用关键字return而不是yield,那么整个函数将在到达return时结束。
return - returns only once
yield - returns multiple times
如果一个函数使用关键字yield,那么它就是一个生成器。
现在你可以这样迭代:
db = MySQLdb.connect(host="localhost", user="root", passwd="root", db="domains")
cursor = db.cursor()
cursor.execute("SELECT domain FROM domains")
for result in ResultGenerator(cursor):
doSomethingWith(result)
db.close()
其他回答
缓冲。当以大块获取数据是有效的,但以小块处理数据时,生成器可能会有所帮助:
def bufferedFetch():
while True:
buffer = getBigChunkOfData()
# insert some code to break on 'end of data'
for i in buffer:
yield i
上面的方法可以让您轻松地将缓冲与处理分开。消费者函数现在可以一个一个地获取值,而不用担心缓冲。
你可以使用生成器的一个实际例子是,如果你有某种形状,你想要遍历它的角、边或其他地方。对于我自己的项目(源代码在这里),我有一个矩形:
class Rect():
def __init__(self, x, y, width, height):
self.l_top = (x, y)
self.r_top = (x+width, y)
self.r_bot = (x+width, y+height)
self.l_bot = (x, y+height)
def __iter__(self):
yield self.l_top
yield self.r_top
yield self.r_bot
yield self.l_bot
现在我可以创建一个矩形,并在它的角上循环:
myrect=Rect(50, 50, 100, 100)
for corner in myrect:
print(corner)
除了__iter__,你可以有一个方法iter_corners,并在myrect.iter_corners()中使用for corner来调用它。使用__iter__更优雅,因为我们可以在for表达式中直接使用类实例名。
简单的解释是: 考虑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
使用生成器,您还可以对无限序列进行迭代,这在迭代容器时当然是不可能的。
请参阅PEP 255中的“动机”部分。
生成器的一个不太明显的用途是创建可中断函数,它允许您在不使用线程的情况下“同时”执行更新UI或运行多个作业(实际上是交错的)。
当我们的web服务器充当代理时,我使用生成器:
客户端从服务器请求一个代理url 服务器开始加载目标url 服务器在获得结果后立即将结果返回给客户机
推荐文章
- 证书验证失败:无法获得本地颁发者证书
- 当使用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中获得所有直接子目录