自始至终,有一个概念,我们一直都在使用,但是我们从来没有认真地去剖析它,这个概念就是 迭代。
迭代的意思就类似于循环,每一次重复的过程被称之为一次迭代的过程,而每一次迭代得到的结果将会被用来作为下一次迭代的初始值,那么提供迭代方法的容器我们称之为迭代器。
通常我们接触的迭代器有序列(序列就是列表、元组、字符串)和字典,它们都支持迭代操作,举例说明:
我们通常使用 for 语句进行迭代,
>>> for i in "来自江南的你":
print(i)
来
自
江
南
的
你
字符串就是一个容器,同时也是一个迭代器,for 语句的作用就是触发这个迭代器的迭代功能,每次从容器里面依次拿出一个数据,这就是所谓的迭代操作。同时,字典和文件也是支持迭代操作的,例如:
>>> dict1 = {1 : 'one', 2 : 'two', 3 : 'three', 4 : 'four'}
>>> for each in dict1:
print("%s -> %s"%(each, dict1[each]))
1 -> one
2 -> two
3 -> three
4 -> four
关于迭代操作,Python提供了两个 BIF:iter() 和 next()
对于一个容器对象,调用 iter() 就得到它的迭代器,调用 next() ,迭代器就会返回下一个值,那么怎么结束呢,如果没有值可以返回了,Python 就会抛出一个 StopIteration 的异常。举例:
>>> string = '来自江南的你'
>>> it = iter(string)
>>> next(it)
'来'
>>> next(it)
'自'
>>> next(it)
'江'
>>> next(it)
'南'
>>> next(it)
'的'
>>> next(it)
'你'
>>> next(it)
Traceback (most recent call last):
File "
next(it)
StopIteration
我们知道 for 语句是自动调用迭代器的,那么通过这两个 BIF 我们大概就能分析出 for 语句的工作原理:
>>> while True:
try:
each = next(it)
except StopIteration:
break
print(each)
来
自
江
南
的
你
大家看到了,我们用 while 语句同样可以还原 for 语句,
>>> for each in string:
print(each)
来
自
江
南
的
你
那么,我们现在讲的是魔法方法,关于迭代器,它的魔法方法一共是两个:__iter__() 和 __next__()
__iter__()
__next__()
没错,它们对应的就是刚才的两个BIF的实现,一个容器如果是迭代器,那么就应该实现 __iter__() 这个魔法方法,这个方法其实是返回迭代器本身,就是 return(self),接下来重点要实现的是 __next__() 这个魔法方法,因为它跌定了迭代器的规则,举个简单的例子:
#斐波那契数列
>>> class Fibs:
def __init__(self):
self.a = 0
self.b = 1
def __iter__(self):
return self
def __next__(self):
self.a, self.b = self.b, self.a + self.b
return self.a
>>> fibs = Fibs()
>>> for each in fibs:
print(each)
1
1
2
3
5
...
这个会没完没了,不能停下来,但是基本功能实现了,下面改进,加一个限制条件(20以内的数列):
>>> for each in fibs:
if each < 20:
print(each)
else:
break
1
1
2
3
5
8
13
我们发现了,我们刚刚实现的这个迭代器的惟一的亮点就是没有终点,我们可以加入一个参数来控制迭代的范围:
>>> class Fibs:
def __init__(self, n = 10):
self.a = 0
self.b = 1
self.n = n
def __iter__(self):
return self
def __next__(self):
self.a, self.b = self.b, self.a + self.b
if self.a > self.n:
raise StopIteration
return self.a
这样就不会没完没了了:
>>> fibs = Fibs()
>>> for each in fibs:
print(each)
1
1
2
3
5
8
而且,你可以控制它的数量,这里改为100:
>>> fibs = Fibs(100)
>>> for each in fibs:
print(each, end = ' ')
1 1 2 3 5 8 13 21 34 55 89
答:迭代是重复反馈过程的活动,其目的通常是为了接近并到达所需的目标或结果。每一次对过程的重复被称为一次“迭代”,而每一次迭代得到的结果会被用来作为下一次迭代的初始值。
答:不是。因为我们耳熟能详的容器像列表,字典,元组都是可以存放数据的,而迭代器就是实现了__next__()方法的对象(用于遍历容器中的数据)。
答:迭代器性质决定没有办法回退,只能往前进行迭代。但这并不是什么很大的缺点,因为我们几乎不需要在迭代途中进行回退操作。
答:判断该容器是否拥有 __iter__() 和 __next__() 魔法方法。
答:迭代器通过 __next__() 方法每次返回一个元素,并指向下一个元素。如果当前位置已无元素,通过抛出 StopIteration 异常表示。
答:set。对于原生支持随机访问的数据结构(如tuple、list),可以使用迭代器或者下标索引的形式访问,但对于无法随机访问的数据结构 set 而言,迭代器是唯一的访问元素的方式。
for each in range(5):
print(each)
代码清单:
alist = range(5)
it = iter(alist)
while True:
try:
print(next(it))
except StopIteration:
break
>>> leapYears = LeapYear()
>>> for i in leapYears:
if i >=2000:
print(i)
else:
break
2012
2008
2004
2000
提示:闰年判定法((year%4 == 0 and year%100 != 0) or (year%400 == 0))
代码清单:
import datetime as dt
class LeapYear:
def __init__(self):
self.now = dt.date.today().year
def isLeapYear(self, year):
if (year%4 == 0 and year%100 != 0) or (year%400 == 0):
return True
else:
return False
def __iter__(self):
return self
def __next__(self):
while not self.isLeapYear(self.now):
self.now -= 1
temp = self.now
self.now -= 1
return temp
例如:
>>> myRev = MyRev("FishC")
>>> for i in myRev:
print(i, end='')
ChsiF
代码清单:
class MyRev:
def __init__(self, data):
self.data = data
self.index = len(data)
def __iter__(self):
return self
def __next__(self):
if self.index == 0:
raise StopIteration
self.index = self.index - 1
return self.data[self.index]