pyhton中的可迭代对象与迭代器之间的关系, 以及使用__iter__和__next__来构建可迭代对象和迭代器

前言:

关于可迭代对象和迭代器的关系和构建一直理解的都不太深入,今天就自己来深刻扒一扒他们之间的关系!

可迭代对象(iterable):

python中的可迭代对象包括:

  1. list, dict, tuple, str, 用dir()函数查看他们的对象方法都会发现有__iter__()在里面.
  2. 迭代器和生成器也属于可迭代对象
只要有__iter__()方法的对象都是可迭代对象(注意和普通的实例对象区分开).用下面的例子来说明:

先介绍如何来判断是否为可迭代对象:从collections中引入Iterable类

form collections import Iterable
class A:
	def __init__(self):
		pass
class B(A):
	def __iter__(self):
		pass
a = A()
b = B()
isinstance(a, Iterable)   #返回False
isinstance(b, Iterable)   #返回True

可以看出: A类的实例对象a不是可迭代对象, B类继承了A类, 并且又构建了自己的__iter__方法, 所以B的实例对象b是可迭代对象

那么可迭代对象和迭代器又有什神马关系了???

迭代器(iterator):

如果一个可迭代对象有__next__()方法, 那其就是一个迭代器,我们继续用例子来说明:

先介绍如何来判断是否为迭代器:从collections中引入Iterator类

from collections import iterator
class C(B):
	def __next__(self):
		pass
c = C()
isinsatnce(a, Iterable) #返回False
isinstance(b, Iterator) #返回False
isinstance(c, Iterator) #返回True

以上例子可以看出: B类的实例对象b是一个可迭代对象但不是一个迭代器. C类继承了B类, 且C类构建了自己的__next__()方法, 所以C的实例对象c是一个迭代器, 但是A类的实例对象a既不是可迭代对象, 也不是迭代器.


下面介绍__iter__()和__next__()两种魔法方法.

__iter __() 需要返回的是当前对象的 迭代器类的实例, 可以存在两种用法

**(1)**用在可迭代对象内: 看如下示例

class D:
	def __init__(self):
		self.a = [1, 2, 3]
	def __iter__(self):
		return iter(self.a) #slef.a是一个列表(可迭代对象), iter(self.a)调用了列表的__iter__()方法, 返回迭代器类的实例
class E:
	def __init__(self):
		self.a = [1, 2, 3]
	def __iter(self):
		return self    #self就是该实例对象本身, 只是一个可迭代对象实例, 不是一个迭代器实例
d = D()
e = E()
dd = iter(d)  #iter()函数会调用d示例对象的__iter__()方法
ee = iter(e) # 会报错,TypeError: iter() returned non-iterator of type 'E'
isinstance(d, iterator) #返回False, d只是一个可迭代对象, 不是迭代器实例
isinstance(dd, iterator) #返回True

**(2)**还有一个例子:

class F:
	def __init__(self):
		pass
	def __iter__(self):
		return self    #返回self自己, sel本身就是一个迭代器类实例
	def __next__(self):
		pass
f = F()
#f是一个迭代器类实例
ff = iter(f)
isinstance(f, iterator) #返回True
isinstance(ff, iterator) #返回True

__next __():返回迭代器的每一次迭代
例如下定义一个斐波拉切类

class Fib:
	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 + sefl.b
		return self.a
fib = Fib()
fib_iter = iter(fib)  #调用__iter__()方法, 返回一个迭代器类实例
#next函数调用迭代器的__next__()方法,每次返回一个迭代值
next(fib_iter)  # 1
next(fib_iter)  # 1
next(fib_iter)  # 2
next(fib_iter)  # 3
next(fib_iter)  # 5

在python中, 序列(list, str,tuple)以及dict都是属于可迭代对象。 且调用iter()函数之后都会返回他们的迭代器实例

在python中, 使用for函数可以遍历可迭代对象,步骤如下:
1): 首先传入一个可迭代对象
2): python会使用iter()函数调用可迭代对象的__iter__()方法
3): 如果iter()函数返回了一个迭代器实例,若iter()返回的不是一个迭代器实例,则会返回一个类型错误TypeError: iter() returned non-iterator of type ‘A’
4): 逐次地调用Next()方法, 每次返回一个迭代,直到结束为止!

另外: 当然也可以直接给for传入一个可迭代对象

具体实例如下:

class A:
	def __init__(self, max):
		self.max = max
		self.a, self.b = 0, 1
	def __iter__(self):
		return self
class Fib(A):
	def __init__(self, max):
		super().__init__(max)
	def __next__(self):
		if self.b < self.max:
			self.a = self.b
			self.b = self.a + self.b
			return self.a
		raise StopIteration()
a = A(10)       #a是一个可迭代对象, 但iter(a)不是一个迭代器
for i in a:
	print(i)    #会返回错误:TypeError: iter() returned non-iterator of type 'A'
#下面两个都会成功打印出来
fib = Fib(10)
for i in fib:
	print(i)

_fib = iter(fib)
for i in _fib:    #此时的_fib就是一个迭代器实例,而不是可迭代对象
	print(i)

最后来说一下生成器yield

yield

由于迭代器必须要在类中定义实现,为了能够在函数中也可以实现迭代器, 就有了yield

yield 的作用就是把一个函数变成一个generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator.

函数每次运行到yiled之后就会挂起, 然后下一次再被调用,再继续挂起,直到最后结束,自动抛出 StopIteration 异常。具体代码如下:

def fib(max):
	a, b = 0, 1
	while(max > b):
		a = b, 
		b = a+b
		yield a
_fib = fib(10)
isinstance(_fib, Iterator)  #返回True,表示返回的生成器是一个迭代器(iterator)
for i in _fib :
	print(i)
#输出1, 1, 2, 3, 5, 8
#也可以调用该迭代器的__Next__()方法
Next(_fib) #1
Next(_fib) #1
Next(_fib) #2
Next(_fib) #3
Next(_fib) #5
Next(_fib) #8
Next(_fib) # 返回StopIteration
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值