《零基础入门学习Python》第048讲:魔法方法:迭代器

目录

0. 请写下这一节课你学习到的内容:格式不限,回忆并复述是加强记忆的好方式!

测试题(笔试,不能上机哦~)

0. 请用你的话解释一下“迭代”的概念?

1. 迭代器是一个容器吗?

2. 迭代器可以回退(获取上一个值)吗?

3. 如何快速判断一个容器是否具有迭代功能?

4. for 语句如何判断迭代器里边已经取空了?

5. 在 Python 原生支持的数据结构中,你知道哪一个是只能用迭代器访问的吗?

动动手(一定要自己动手试试哦~)

0. 用 while 语句实现与以下 for 语句相同的功能:

1. 写一个迭代器,要求输出至今为止的所有闰年。如:

2. 要求自己写一个 MyRev 类,功能与 reversed() 相同(内置函数 reversed(seq) 是返回一个迭代器,是序列 seq 的逆序显示)。


0. 请写下这一节课你学习到的内容:格式不限,回忆并复述是加强记忆的好方式!

自始至终,有一个概念,我们一直都在使用,但是我们从来没有认真地去剖析它,这个概念就是 迭代

迭代的意思就类似于循环,每一次重复的过程被称之为一次迭代的过程,而每一次迭代得到的结果将会被用来作为下一次迭代的初始值,那么提供迭代方法的容器我们称之为迭代器

通常我们接触的迭代器有序列(序列就是列表、元组、字符串)和字典,它们都支持迭代操作,举例说明:

我们通常使用 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 "<pyshell#47>", line 1, in <module>
    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()

__iter__()

  • next()

__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 

测试题(笔试,不能上机哦~)

0. 请用你的话解释一下“迭代”的概念?

答:迭代是重复反馈过程的活动,其目的通常是为了接近并到达所需的目标或结果。每一次对过程的重复被称为一次“迭代”,而每一次迭代得到的结果会被用来作为下一次迭代的初始值。

1. 迭代器是一个容器吗?

答:不是。因为我们耳熟能详的容器像列表,字典,元组都是可以存放数据的,而迭代器就是实现了__next__()方法的对象(用于遍历容器中的数据)。

2. 迭代器可以回退(获取上一个值)吗?

答:迭代器性质决定没有办法回退,只能往前进行迭代。但这并不是什么很大的缺点,因为我们几乎不需要在迭代途中进行回退操作。

3. 如何快速判断一个容器是否具有迭代功能?

答:判断该容器是否拥有 __iter__() 和 __next__() 魔法方法。

4. for 语句如何判断迭代器里边已经取空了?

答:迭代器通过 __next__() 方法每次返回一个元素,并指向下一个元素。如果当前位置已无元素,通过抛出 StopIteration 异常表示。

5. 在 Python 原生支持的数据结构中,你知道哪一个是只能用迭代器访问的吗?

答:set。对于原生支持随机访问的数据结构(如tuple、list),可以使用迭代器或者下标索引的形式访问,但对于无法随机访问的数据结构 set 而言,迭代器是唯一的访问元素的方式。


动动手(一定要自己动手试试哦~)

0. 用 while 语句实现与以下 for 语句相同的功能:

for each in range(5):
    print(each)

代码清单:

alist = range(5)
it = iter(alist)

while True:
    try:
        print(next(it))
    except StopIteration:
        break

1. 写一个迭代器,要求输出至今为止的所有闰年。如:

>>> 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

2. 要求自己写一个 MyRev 类,功能与 reversed() 相同(内置函数 reversed(seq) 是返回一个迭代器,是序列 seq 的逆序显示)。

例如:

>>> 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]

 

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值