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

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

时间:2023-03-26 12:40:22 Python

上一节(5.2包装)|下一节(6.2自定义迭代)6.1迭代协议本节将探讨迭代的底层过程。迭代无处不在许多对象支持迭代:a='hello'forcina:#Loopovercharactersina...b={'name':'Dave','password':'foo'}forkinb:#遍历字典中的键...c=[1,2,3,4]foriinc:#遍历列表/元组中的项目...f=open('foo.txt')forxinf:#循环文件中的行...Iteration:Protocol考虑以下for语句:forxinobj:#for语句后面发生了什么?_iter=obj.__iter__()#获取迭代器对象whileTrue:try:x=_iter.__next__()#Getnextitem#statements...exceptStopIteration:#Nomoreitemsbreak所有可以应用于for循环的对象都实现上面的底层迭代协议。示例:手动迭代列表。>>>x=[1,2,3]>>>it=x.__iter__()>>>it>>>it.__next__()1>>>it.__next__()2>>>it.__next__()3>>>it.__next__()Traceback(最后一次调用):文件“”,第1行,在?StopIteration>>>支持迭代如果你想给自己的对象添加迭代,了解迭代是很有用的。例如:自定义容器。classPortfolio:def__init__(self):self.holdings=[]def__iter__(self):returnself.holdings.__iter__()...port=Portfolio()forsinport:...Exercise练习6.1:迭代演示创建如下列表:a=[1,9,4,25,16]请手动迭代列表:首先调用__iter__()方法获取迭代器,然后调用__next__()方法获取下一个元素.>>>i=a.__iter__()>>>i>>>i.__next__()1>>>i.__next__()9>>>i.__next__()4>>>i.__next__()25>>>i.__next__()16>>>i.__next__()Traceback(最近调用最后):文件“”,第1行,在StopIteration>>>内置-in函数next()是调用迭代器的__next__()方法的快捷方式。尝试在文件对象上使用next()方法:>>>f=open('Data/portfolio.csv')>>>f.__iter__()#注意:这会返回文件本身<_io.TextIOWrappername='Data/portfolio.csv'mode='r'encoding='UTF-8'>>>>next(f)'name,shares,price\n'>>>next(f)'"AA",100,32.20\n'>>>next(f)'"IBM",50,91.10\n'>>>不断调用next(f)直到文件结束。看看会发生什么。练习6.2:支持迭代有时,你可能想让你的类对象支持迭代——尤其是当你的类对象封装了一个现有的列表或其他可迭代对象时。请在新的portfolio.py文件中定义以下类:self._holdings])deftabulate_shares(self):fromcollectionsimportCountertotal_shares=Counter()forsinself._holdings:total_shares[s.name]+=s.sharesreturntotal_sharesPortfolio类封装了一个列表并且有一些方法,例如作为:total_cost属性。请修改report.py文件中的read_portfolio()函数,以便read_portfolio()函数创建Portfolio类的实例,如下所示:'''将股票投资组合文件读入包含名称、股票和价格键的字典列表中。'''withopen(filename)asfile:portdicts=fileparse.parse_csv(file,select=['name','shares','price'],types=[str,int,float])portfolio=[Stock(d['name'],d['shares'],d['price'])fordinportdicts]returnPortfolio(portfolio)...然后运行??report.py程序。您会发现程序失败的原因很明显,因为Portfolio实例不是可迭代对象。>>>importreport>>>report.portfolio_report('Data/portfolio.csv','Data/prices.csv')...崩溃...您可以通过修改Portfolio类以支持迭代来解决此问题:类投资组合:def__init__(self,holdings):self._holdings=holdingsdef__iter__(self):returnself._holdings.__iter__()@propertydeftotal_cost(self):returnsum([s.shares*s.priceforsinself._holdings])deftabulate_shares(self):fromcollectionsimportCountertotal_shares=Counter()forsinself._holdings:total_shares[s.name]+=s.sharesreturntotal_shares修改后report.py程序应该能够再次正常运行。此外,修改pcost.py程序以使用新的投资组合对象,如下所示:#pcost.pyimportreportdefportfolio_cost(filename):'''计算投资组合文件的总成本(股票*价格)read_portfolio(filename)returnportfolio.total_cost...测试pcost.py程序以确保其正常工作:>>>importpcost>>>pcost.portfolio_cost('Data/portfolio.csv')44671.15>>>练习6.3:创建一个更合适的容器通常,我们在创建一个容器类的时候,不仅希望这个类可以迭代,还希望这个类可以有一些其他的用途。修改Portfolio类以具有这些特殊方法:._holdings)def__getitem__(self,index):returnself._holdings[index]def__contains__(self,name):returnany([s.name==nameforsinself._holdings])@propertydeftotal_cost(self):returnsum([s.shares*s.priceforsinself._holdings])deftabulate_shares(self):fromcollectionsimportCountertotal_shares=Counter()forsinself._holdings:total_shares[s.name]+=s.sharesreturntotal_shares现在,用Portfolio类做一些实验:>>>importreport>>>portfolio=report.read_portfolio('Data/portfolio.csv')>>>len(portfolio)7>>>投资组合[0]股票('AA',100,32.2)>>>投资组合[1]股票('IBM',50,91.1)>>>投资组合[0:3][Stock('AA',100,32.2),Stock('IBM',50,91.1),Stock('CAT',150,83.44)]>>>投资组合中的“IBM”为真>>>'AAPL'inportfolioFalse>>>关于上述代码的一个重要发现——一般来说,如果一段代码“说出了Python其他部分通常如何工作的通用词汇”,那么该代码被认为是“以与“Pythonic”,对于容器对象,其重要组成部分应该包括:支持迭代、索引、判断包含元素等操作等内容|上一节(5.2封装)|下一节(6.2自定义迭代)注:见https://github.com/codists/practical-python-zh完整翻译

猜你喜欢