python迭代器详解,python语言编程中迭代器
Yyds干货库存
你还记得你上次丢东西是什么时候吗?
你可能会翻遍你的房子。一个房间一个房间的搜,而周围的人问一些没有意义的问题,比如“你上次放在哪里了?”说真的,如果我知道,我就不会给他们打电话了!)如果你优化了你的搜索方式,那就好办了,但是你的房子和房间没有排序……或者说特别有条理。如果你和我一样,被线性搜索困住了。
在编程中,就像在现实生活中一样,我们通常得不到任何有意义的序列数据。它通常以一片混乱开始,我们必须在它上面执行任务。搜索无序数据可能是第一个想到的例子,但您可能还想做数百件其他事情:将所有华氏温度记录转换为摄氏温度,找到所有数据点的平均值,等等。
“没错,回收就是为了这个!”
但这是Python。它的周期在完全不同的层面上。它们很容易使用。
让我们扔掉那些无聊的东西,好吗?
像大多数语言一样,Python中有两个基本循环:while和for。
While while循环非常基础。
线索=无
而线索是没有:
clue=searchLocation()
在这种情况下,只要循环条件的评估结果为真,就会执行循环代码。
在Python中,我们还有几个有用的关键字:break立即停止循环,而continue跳转到循环的下一次迭代。
break最有用的一个方面是,如果我们希望运行相同的代码,直到用户提供有效的输入。
虽然正确:
尝试:
age=int(input(输入您的年龄: ))
除了值错误:
请输入一个有效的整数!)
否则:
如果年龄为0:
破裂
一旦遇到break语句,我们就退出循环。当然,以上是比较复杂的例子,但证明了这一点。你也经常看到while True:用在游戏循环中。
注意:如果你曾经在任何语言中使用过循环,那么你已经对无限循环(无限循环)很熟悉了。这通常是由于while条件评估为True,并且循环中没有break语句。
For来自Java、C或许多类似的ALGOL风格的语言。你可能对三路for循环比较熟悉:for I:=1;i 100我:=i 1 .我不知道你怎么样,但是我第一次遇到这种情况的时候,把我吓坏了。我现在很满意,但是没有Python的优雅简洁。
Python的for循环看起来很不一样。与上述伪代码等价的Python代码是.
对于在幅度内的I(1,100):
打印(一)
Range()是Python中一个特殊的“函数”,它返回一个序列。(技术上来说,根本不是函数。)
这就是Python ——让人印象深刻的地方。它迭代一种特殊类型的序列,称为iterable,我们将在后面讨论。
目前最容易理解的是,我们可以迭代一个顺序数据结构,比如数组(Python中称为“list”)。
因此,我们可以这样做。
places=[纳什维尔,挪威,博内尔,津巴布韦,芝加哥,捷克斯洛伐克]
对于地点中的地点:
打印(地点)
打印(.“回来!”)
我们明白了。
纳什维尔
挪威
博奈尔岛
津巴布韦
芝加哥
捷克斯洛伐克
.又回来了!
为.elsePython的循环中还有另一个独特的技巧:else子句!循环完成后,else将在没有break语句的情况下运行。但是,如果手动中断循环,它将完全跳过else。
places=[纳什维尔,挪威,博内尔,津巴布韦,芝加哥,捷克斯洛伐克]
恶棍_at=马里
对于地点中的地点:
if place==恶棍_at:
打印(恶棍被捕!)
破裂
否则:
打印(恶棍又跑了。)
由于“马里”不在列表中,我们看到了“恶棍又跑了”的消息。但是,如果我们把反派_at的值改成挪威,就会看到“反派被俘!”而看不到“反派又跑了。”。
有do吗.怀尔。没有Python做的.while循环。如果您正在寻找这样的循环,典型的Python使用while True:with internal break condition,正如我们之前演示的那样。
数据(容器)Python有许多容器或数据结构来保存数据。我们不会深入讨论其中任何一个,但我想快速浏览一下最重要的部分:
list列出一个变量序列(实际上是一个数组)。
它由方括号[]定义,您可以通过索引访问它的元素。
foo=[2,4,2,3]
print(foo[1])
四
foo[1]=42
打印
[2, 42, 2, 3]
虽然对它没有严格的技术要求,但是典型的惯例是列表只包含相同类型的元素(“同质”)。
Tupletuple是不可变的序列。一旦你定义了它,你就不能在技术上改变它(回想一下之前不变性的含义)。这意味着在定义了一个元组之后,就不能在元组中添加或删除元素了。
元组在括号()中定义,可以通过索引访问它的元素。
foo=(2,4,2,3)
print(foo[1])
四
foo[1]=42
type error:“tuple”对象不支持项分配
与列表不同,标准约定允许元组包含不同类型的元素(“异类”)。
Setset是一个无序的变量集,它保证没有重复。记住“无序”很重要:不能保证单个元素的顺序!
集合是用花括号{}定义的,但是如果你想要一个空集,你可以用foo=set()或者foo={}来创建一个空字典。你不能通过索引访问它的元素,因为它是无序的。
foo={2,4,2,3}
打印
{2, 3, 4}
print(foo[1])
类型错误:“set”对象不支持索引
对于要添加到集合中的对象,它也必须是hash。如果满足以下条件,则对象是可哈希的:
它定义了方法__hash__(),该方法将哈希值(hash)作为整数返回。(见下文)它定义了__eq__()如何比较两个对象。对于同一个对象(值),一个有效的哈希值(hash)应该总是相同的,并且应该是合理唯一的,所以另一个对象返回相同的hash并不常见。(两个或两个以上具有相同哈希值的对象称为哈希冲突,并且仍然会发生。)
Dictdict(字典)是一种键值数据结构。
它在花括号中定义了{}:用于分隔键和值。它是无序的,所以你不能通过索引访问它的元素;但是您可以通过[]添加键值来访问元素。
foo={a : 1, b : 2, c : 3, d : 4}
print(foo[b])
2
foo[b]=42
打印
{a: 1, b: 42, c: 3, d: 4}
只有可哈希的对象可以用作字典键。(关于set hashing的更多信息,请参见官网部分。)
除了这些基础,Python还提供了额外的容器/数据结构。您可以在内置模块集合中找到它们。
解包有一个重要的Python语法,我们还没有讨论,但它很快就会派上用场。我们可以将容器中的每个元素赋给一个变量!这叫拆包。
当然,我们需要确切地知道需要解包多少才能完成,否则我们将得到一个ValueError异常。
让我们看一个使用元组的基本例子。
全名=(卡门,桑迪戈)
名字,姓氏=全名
打印(第一页)
卡门
打印(最后)
圣地牙哥
查看第二行代码,我们可以列出多个要赋值的变量,用逗号分隔。Python会将容器拆分到等号的右边,并按照从左到右的顺序将每个值赋给一个变量。
注意:记住,集合是无序的!尽管从技术上来说,您可以使用集合来实现这一点,但是您无法确定将什么值赋给什么变量。保证分布不按顺序,集合的值的分布顺序通常是偶然的!
InPython在中提供了一个关键字,用于检查是否在容器中找到了特定的元素。
places=[纳什维尔,挪威,博内尔,津巴布韦,芝加哥,捷克斯洛伐克]
如果“纳什维尔”在某些地方:
打印(音乐城!)
这适用于许多容器,包括列表、元组、集甚至字典键(但不包括字典值)。
如果您希望您的自定义类之一支持in运算符,您只需定义__contains__(self,item)方法,该方法应返回True或False。
迭代器Python的循环与我前面提到的迭代器结合使用。前面提到的数据结构都是可以被迭代器迭代的对象。
好吧,我们从头说起。Python容器对象(如list)也是可迭代对象,因为它的__iter__()方法返回迭代器对象。
方法__next__()也是一个迭代器,它在容器迭代器的情况下返回下一项。即使是无序的容器,比如set(),也可以被迭代器遍历。
当__next__()不能返回任何其他内容时,它会抛出一个名为StopIteration的特殊异常。这可以用试试.除了捕捉异常。
例如,让我们再来看看遍历列表的循环.
档案=[伯爵夫人,双重麻烦,地球蛮, Kneemoi ,帕蒂盗窃罪, RoboCrook ,莎拉纳德,顶级垃圾,维克滑头,神奇鼠]
对于档案中的骗子:
打印(弯曲)
档案是一个列表对象,这是一个迭代对象。当Python到达for循环时,它会做三件事:
调用iter(档案)并执行档案。__iter__()依次。这将返回一个迭代器对象list_iter,我们将调用它。这个迭代器对象将被回收。对于循环的每次迭代,它调用next (list _ iterator),执行list _ iterator。_ _ next _ _()并将返回值赋给crook。如果迭代器抛出一个特殊的异常StopIteration,循环结束并退出。虽然正确:如果我在一个循环中重写逻辑,可能会更容易理解。
list_iter=iter(档案)
虽然正确:
尝试:
crook=next(list_iter)
打印(弯曲)
除了StopIteration:
破裂
如果你尝试这两个循环,你会发现它们做的完全一样!
在理解__iter__()、__next__()和StopIteration异常是如何工作的之后,现在可以让自己的类迭代了!
注意:虽然你可以从迭代器类中单独定义迭代器类,但是你不一定要这样做!只要在类中定义了这两个方法,并且__next__()行为正常,就可以将__iter__()定义为return self。
值得注意的是,迭代器本身是迭代的:它们有一个__iter__()方法返回self。
字典案例假设我们有一本想要使用的字典。
位置={
阅兵场:无,
Ste。-凯瑟琳街:无,
维多利亚桥:没有,
地下城:无,
“皇家公园山”:无,
美术馆:无,
“幽默名人堂”:“通缉令”,
拉钦运河:战利品,
蒙特利尔爵士音乐节:无,
奥林匹克体育场:无,
《圣劳伦斯河》:《溪边》,
“旧蒙特利尔”:无,
“麦吉尔大学”:无,
“木屋了望”:无,
圣母院:没有
}
如果我们只想查看其中的每一项,我们只需要使用for循环。所以,这应该是可行的,对吧?
对于位置中的位置:
打印(位置)
哦亲爱的!这只向我们展示了关键,而不是价值。这不是我们想要的,是吗?
迪克特。__iter__()返回一个dict_keyiterator对象,该对象执行其类名的操作:它遍历键,但不遍历值。
为了同时获得键和值,我们需要调用locations.items()来返回dict_items对象。Dict_items.iter()返回dict_itemiterator,它将字典中的每个键值对作为一个元组返回。
旧版本说明:如果你用的是Python 2,应该改为调用locations.iteritems()。
还记得刚才我们谈到拆包吗?我们将每个键值对视为一个元组,并将其分成两个变量。
对于键,locations.items()中的值:
print(f“{ key }={ value }”)
打印出以下内容:
阅兵场=无
Ste。-凯瑟琳街=无
维多利亚桥=无
地下城=无
皇家公园山=无
美术馆=无
幽默名人堂=搜查令
拉钦运河=战利品
蒙特利尔爵士音乐节=无
奥林匹克体育场=无
圣劳伦斯河=溪边
旧蒙特利尔=无
麦吉尔大学=无
木屋了望台=无
圣母院=无
现在我们可以处理数据了。例如,我想在另一本字典中记录重要信息。
信息={}
对于location,结果为locations.items():
如果结果不是无:
信息[结果]=位置
#赢得比赛!
打印(信息[战利品])
打印(信息[搜查令])
打印(信息[骗子])
打印(“维克的滑头.“在jaaaaaaaaail!”)
这将找到战利品,权证和骗子,并列出他们在正确的顺序:
拉钦运河
幽默名人堂
圣劳伦斯河
滑头维克.在jaaaaaaaaail!
自定义迭代器我之前提到过你可以自己做迭代器和迭代器,但是现在让我们来实现它!
假设我们想要方便地保存一个代理列表,这样我们就可以通过它们的编号来识别它们。然而,有一些代理我们不能谈论。我们可以通过将代理ID和名称存储在字典中,然后维护一个分类代理列表来轻松实现这一点。
注意:请记住,在我们对类的讨论中,Python中实际上没有私有变量这种东西。如果你真的想保密,请使用行业标准的加密和安全措施,或者至少不要将你的API暴露给任何恶意的操作者。)
对于初学者来说,这是这个类的基本结构:
班级代理花名册:
def __init__(self):
自我。_agents={}
自我。_classified=[]
def add_agent(自身,名称,编号,已分类=False):
自我。_agents[number]=name
如果分类:
自我。_classified.append(名称)
def validate_number(self,number):
尝试:
名字=自我。_代理人[数量]
除了KeyError:
返回False
否则:
返回True
定义查找_代理人(自身,编号):
尝试:
名字=自我。_代理人[数量]
除了KeyError:
name=未知代理
否则:
如果名字在自己身上。_分类:
name=分类
返回名称
我们可以继续测试,只是为了后续:
花名册=代理花名册()
花名册. add_agent(安蒂克威,2539634)
花名册. add_agent(伊凡点子,1324595)
花名册. add_agent(坚如磐石,1385723)
花名册. add_agent(Chase Devineaux ,1495263,True)
打印(花名册.验证号码(2539634))
真实的
打印(花名册.验证号码(9583253))
错误的
打印(花名册. lookup_agent(1324595))
伊凡的主意
打印(花名册. lookup_agent(9583253))
未知代理
打印(花名册. lookup_agent(1495263))
分类的
太好了,这完全符合预期!现在,如果我们希望能够遍历整个字典。
但是,我们不想直接访问花名册。_agents字典,因为这将忽略该类的整个“分类”方面。我们该如何处理?
正如我之前提到的,我们可以让这个类充当自己的迭代器,这意味着它有一个__next__()方法。在这种情况下,我们只会回归自我。然而,这里有一个超级简单的Python教程,所以让我们跳过烦人的步骤,简化内容,实际上创建一个单独的迭代器类。
在这个例子中,我实际上把字典变成了元组列表,这将允许我使用索引。记住,字典是无序的。)我也会算算有多少特工未分类。当然,所有这些逻辑都属于这个__init__()方法:
类代理名册_迭代器:
def __init__(自身,容器):
自我。_花名册=列表(容器。_ agents.items())
自我。_ classified=容器。_机密
自我。_max=len(self。_花名册)- len(self。_分类)
自我。_index=0
要成为迭代器,类必须有__next__()方法;这是唯一的要求!记住,一旦我们没有更多的数据要返回,这个方法需要抛出一个StopException异常。
我将AgentRoster_Iterator的__next__()方法定义如下:
类代理名册_迭代器:
# .剪.
def __next__(自己):
如果自我。_index==self。_max:
提升停止迭代
否则:
r=自我。_花名册[self。_index]
自我。_index=1
返回r
现在我们回到AgentRoster类,在这里我们需要添加__iter__()的方法来返回迭代器对象。
班级代理花名册:
# .剪.
def __iter__(self):
返回agent花名册_迭代器(self)
这只需要一点点操作,现在我们的AgentRoster类的行为完全符合循环的预期!这段代码如下.
花名册=代理花名册()
花名册. add_agent(安蒂克威,2539634)
花名册. add_agent(伊凡点子,1324595)
花名册. add_agent(坚如磐石,1385723)
花名册. add_agent(Chase Devineaux ,1495263,True)
对于编号,花名册中的名称:
打印(f { name },id #{number} )
结果如下.
安蒂克威,身份证号2539634
伊凡创意,id号1324595
坚如磐石,id号1385723
一直期待我听到后面的皮托尼斯塔:“等等,等等,我们还不能完成它!你连列表解析都没接触过!”
Python确实为循环和迭代器增加了一个额外的层次,它使用了一个叫做generator的特殊工具。这种类型的类提供了另一个不可思议的工具,称为理解,它就像一个创建数据结构的完美闭环。
我还故意跳过了zip()和enumerate()的优点,让循环和迭代更加强大。我就在这里总结一下,但不希望文章太长。这些我后面也会讲。
我猜你们中的一些人已经在期待了,但是不幸的是,你将不得不等到下一篇文章来了解更多。
总结让我们回顾一下本节中最重要的概念:
只要while的计算结果为,循环将运行True。你可以使用关键字跳出循环断点,或者使用关键字跳到下一个迭代继续。for循环遍历一个可迭代的对象(可以被迭代的对象),比如一个列表。range()函数返回一个迭代的数字序列,可以在for循环中使用,例如对于range(1,100)中的I。Python没有do.while循环。使用while True:带有显式break语句的循环。Python有四种基本的数据结构或容器:列表是一种可变的、有序的、顺序的结构……基本上是一个数组。元组是不可变的、有序的和顺序的结构。想想清单,但不能修改内容。集合是一个可变的无序结构,保证不会有重复的元素。它们只能存储散列对象。字典是一种可变的无序结构,用于存储键值对。你通过关键字而不是索引来查找条目。只有可哈希的对象可以用作键。你可以用约定把一个容器的值拆分成多个变量a,b,c=someContainer。左侧容器中变量的数量和右侧容器中元素的数量必须相同!您可以使用关键字快速检查元素是否在容器中。如果您希望您的类支持这一点,请定义contains()方法。Python的容器是可迭代对象的例子:它们返回可以遍历其内容的迭代器。迭代对象总是通过iter iterator()方法返回一个iterator对象。迭代器对象总是有一个返回一个值的方法next()。容器迭代器的next()方法将返回容器中的下一个元素。当没有更多的东西要返回时,迭代器抛出一个StopIteration异常。原创作品来自程,
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。