当前位置: 首页 > 后端技术 > Python

翻译:《实用的Python编程》06_02_Customizing_iteration

时间:2023-03-25 21:26:01 Python

内容|上一节(6.1迭代协议)|下一节(6.3生产者/消费者)6.2自定义迭代本节探讨如何使用生成器函数来自定义迭代。该问题假定您要自定义迭代模式。例如:Countdown:>>>forxincountdown(10):...print(x,end='')...10987654321>>>有一个简单的方法做到这一点。生成器是定义迭代的函数:defcountdown(n):whilen>0:yieldnn-=1示例:>>>forxincountdown(10):...print(x,end='')...10987654321>>>任何使用yield语句的函数都称为生成器。生成器函数的行为与普通函数不同。调用生成器函数会创建一个生成器对象,而不是立即执行该函数:defcountdown(n):#Addedaprintstatementprint('Countingdownfrom',n)whilen>0:yieldnn-=1>>>x=countdown(10)#ThereisNOPRINTSTATEMENT>>>x#xisageneratorobject>>>生成器函数仅在调用__next__()方法时执行:>>>x=countdown(10)>>>x>>>x.__next__()Countingdownfrom1010>>>yield生成一个值,但暂停函数执行。生成器函数会在下一次调用__next__()方法时恢复(resume),>>>x.__next__()9>>>x.__next__()8当生成器返回最后一个值时,会触发另一次迭代错误(译注:StopIteration)。>>>x.__next__()1>>>x.__next__()Traceback(最后一次调用):文件“”,第1行,在?StopIteration>>>观察:生成器函数实现的协议与for语句对列表、元组、字典和文件使用相同的底层协议。练习练习6.4:一个简单的生成器如果你想自定义迭代,那么你应该始终考虑生成器函数。生成器函数非常容易编写——创建一个函数,执行所需的迭代逻辑,然后使用yield发送一个值。例如,要创建一个在文件的每一行中查找匹配子字符串的生成器:>>>deffilematch(filename,substr):withopen(filename,'r')asf:forlineinf:ifsubstr行:yieldline>>>forlineinopen('Data/portfolio.csv'):print(line,end='')name,shares,price"AA",100,32.20"IBM",50,91.10"CAT",150,83.44"MSFT",200,51.23"GE",95,40.37"MSFT",50,65.10"IBM",100,70.44>>>forlineinfilematch('Data/portfolio.csv','IBM'):print(line,end='')"IBM",50,91.10"IBM",100,70.44>>>这是一个有趣的想法——你可以在函数中隐藏自定义处理,并应用for循环的函数。下一个示例探讨了一种更不寻常的情况。练习6.5:监控流数据源生成器可用于监控实时数据源(例如:日志文件、股市新闻)。在本节中,我们探索使用生成器监控实时数据源的想法。首先,请严格按照以下说明进行操作。data/stocksim.py用于模拟股市数据,不断将实时数据写入Data/stocklog.csv文件。请打开一个独立的命令行窗口,进入Data/目录,然后运行stocksim.py程序:bash%python3stocksim.py如果您使用的是Windows系统,请找到stocksim.py文件,然后双击单击该文件以运行它。那么,我们先把这个程序放在一边(让它在那里运行),再打开一个命令行窗口,看看模拟程序正在写入的Data/stocklog.csv文件(译注:stocksim.py)(译注:如果你在使用Linux系统,可以进入Data目录,然后使用tail-fstocklog.csv命令查看)。您应该每隔几秒就会看到新的文本行被添加到Data/stocklog.csv文件中。另外,让程序在后台运行——程序会运行几个小时(不用担心)。随着stocksim.py程序的运行,让我们编写一个程序来打开Data/stocklog.csv文件,移动到文件的末尾,并查看新的输出。请在Work目录下创建一个follow.py文件,并将以下代码放入其中:#follow.pyimportosimporttimef=open('Data/stocklog.csv')f.seek(0,os.SEEK_END)#移动文件pointer0bytesfromendoffilewhileTrue:line=f.readline()ifline=='':time.sleep(0.1)#短暂休眠并重试继续fields=line.split(',')name=fields[0].strip('"')price=float(fields[1])change=float(fields[4])ifchange<0:print(f'{name:>10s}{price:>10.2f}{change:>10.2f}')运行follow.py程序,你会看到实时股票行情(stockticker)。follow.py中的代码类似于Unix系统中tail-f命令查看日志注意:在此示例中,readline()方法的使用方式与从文件中读取行的常用方式(通常使用for循环)略有不同。在这种情况下,我们使用readline()反复探测文件末尾以查看是否添加了新数据(readline()方法返回新数据或空字符串)。练习6.6:使用生成器生成数据查看练习6.5中的代码,您会注意到代码的第一部分生成几行数据,而while循环末尾的语句使用数据。生成器的一个关键特性是您可以将生成数据的代码移动到可重用的函数中。修改练习6.5中的代码,通过生成器函数follow(filename)执行文件读取。请实施更改,以便以下代码起作用:>>>forlineinfollow('Data/stocklog.csv'):print(line,end='')...应该看到此处生成的输出行...请修改股票报价代码,使代码看起来像这样:if__name__=='__main__':forlineinfollow('Data/stocklog.csv'):fields=line.split(',')name=fields[0].strip('"')price=float(fields[1])change=float(fields[4])ifchange<0:print(f'{name:>10s}{price:>10.2f}{change:>10.2f}')练习6.7:查看股票投资组合请修改follow.py程序,以便该程序可以查看股票数据流并打印有关股票投资组合中这些股票的信息。示例:if__name__=='__main__':importreportportfolio=report.read_portfolio('Data/portfolio.csv')forlineinfollow('Data/stocklog.csv'):fields=line.split(',')name=fields[0].strip('"')price=float(fields[1])change=float(fields[4])ifnameinportfolio:print(f'{name:>10s}{price:>10.2f}{change:>10.2f}')注意:要让这段代码正常工作,Portfolio类必须支持in运算符。请参阅练习6.3以确保Portfolio类实现__contains__()运算符。在此处讨论,您将一个有趣的迭代模式(读取文件末尾的行)移动到一个函数中。follow()函数现在是一个完全通用的实用程序,可以在任何程序中使用。例如,您可以使用follow()功能查看服务器日志、调试日志和其他类似数据源。内容|上一节(6.1迭代协议)|下一节(6.3生产者/消费者)注:完整翻译见https://github.com/codists/practical-蟒蛇-zh

猜你喜欢