python中for循环的原理剖析
简述当我们在使用for循环时,即重复运行一个代码块,或者不断迭代容器对象中的元素,比如一些序列对象,列表,字典,元组,甚至文件等,而for循环的本质取出可迭代对象中的迭代器然后对迭代器不断的操作。例如迭代文件:注:本文针对的示例是针对Python3,同时对Python2做了注释,注意区分自己使用的版本。>>> for line in open("requirement.t...
·
简述
- 当我们在使用for循环时,即重复运行一个代码块,或者不断迭代容器对象中的元素,比如一些序列对象,列表,字典,元组,甚至文件等,而for循环的本质取出可迭代对象中的迭代器然后对迭代器不断的操作。
- 容器是一系列元素的集合,str、list、set、dict、file、sockets对象都可以看作是容器,容器都可以被迭代(用在for,while等语句中),因此他们被称为可迭代对象。
- 可迭代对象实现了__iter__方法,该方法返回一个迭代器对象。
- 迭代器持有一个内部状态的字段,用于记录下次迭代返回值,它实现了__next__和__iter__方法,迭代器不会一次性把所有元素加载到内存,而是需要的时候才生成返回结果。
- 生成器是一种特殊的迭代器,它的返回值不是通过return而是用yield。
例如迭代文件:
注:本文针对的示例是针对Python3,同时对Python2做了注释,注意区分自己使用的版本。
>>> for line in open("requirement.txt"):
... print(line, end="")
...
Fabric==1.12.0
Markdown==2.6.7
for循环原理
可迭代对象需要实现__iter__方法,并返回一个迭代器,什么是迭代器呢?迭代器只需要实现 __next__方法。
>>> test=[23,12,45,12]
>>> obj=test.__iter__()#有此方法,说明列表是可迭代对象
>>> obj
<list_iterator object at 0x039983D0>
>>> obj.__next__()#有此方法,说明obj是迭代器
23
>>> obj.__next__()
12
>>> obj.__next__()
45
>>> obj.__next__()
12
>>> obj.__next__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>>
列表是一个可迭代对象,因为它实现了 __iter__方法,并且返回了一个迭代器对象(list_iterator),因为它实现了 __next__方法。我们看到它不断地调用__next__方法,其实就是不断地迭代获取容器中的元素,直到容器中没有更多元素抛出 StopIteration 异常为止。(在Python2中,实现迭代器变成了没有下划线的 next 方法)
- 先判断对象是否为可迭代对象,不是的话直接报错,抛出TypeError异常,是的话,调用 __iter__方法,返回一个迭代器
- 不断地调用迭代器的__next__方法,每次按序返回迭代器中的一个值
- 迭代到最后,没有更多元素了,就抛出异常 StopIteration,这个异常 python 自己会处理,不会暴露给开发者
弄明白了 for 的执行原理之后,我们就可以实现自己的迭代器用在 for 循环中:
例1:
class Test:
def __init__(self, number):
self.i = 0
self.number = number
def __iter__(self):
return self
def __next__(self):
if self.i < self.number:
i = self.i
self.i += 2
return i
else:#当self.i>=self.number时停止迭代
raise StopIteration()
for j in Test(10):
print(j)
例2:
class Account():
def __init__(self,
account_name,
account_type,
account_cost,
return_amount=0):
self.account_name = account_name # 账户名
self.account_type = account_type # 账户类型
self.account_cost = account_cost # 月结费用
self.return_amount = return_amount # 返还金额
class AccountIterator():
def __init__(self, accounts):
self.accounts = accounts # 账户集合
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index >= len(self.accounts):
raise StopIteration("到头了...")
else:
self.index += 1
return self.accounts[self.index - 1]
accounts = [Account("张三", "年费用户", 450.00, 50),
Account("李四", "月结用户", 100.00),
Account("杨不悔", "月结用户", 190.00, 25),
Account("任我行", "月结用户", 70.00, 10),
Account("凌未风", "年费用户", 400.00, 40)]
for i in AccountIterator(accounts):
print(i.account_name)
更多推荐
已为社区贡献4条内容
所有评论(0)