__getitem__、__iter__、__next__、iter和next
方法时,感到比较困惑,于是抽空把这几个方法放在一起介绍一下,免得自己再犯迷糊。
iter(object[, sentinel])
- object:
必须
是实现了__iter__()
方法或者__getitem__()
方法。(如果两个都没有实现,则不能使用iter方法
)- 如果给定了第二个参数sentinel,则object必须是一个
可调用的对象
,此时,iter创建了一个迭代器对象,每次调用这个迭代器对象的__next__()
方法时,都会调用object。如果__next__
的返回值等于sentinel,则抛出StopIteration
异常,否则返回下一个值。
next(iterable[, default])
- iterable – 可迭代对象
- default – 可选,
用于设置在没有下一个元素时返回该默认值
,如果不设置,又没有下一个元素则会触发 StopIteration 异常。
列表、元组、字符串、集合、字典均可使用迭代器
#列表、元组、字符串、集合、字典均可使用迭代器
m_list = [1, 2, 3]
m_tuple = (1,2,3)
m_str = 'qlee'
m_set = {1,2,3}
m_dict = {1:'apple', 2:'pear'}
print('=============iter测试================')
for i in iter(m_list):
print(i,end=',')
print('end list test!')
for i in iter(m_tuple):
print(i,end=',')
print('end tuple test!')
for i in iter(m_str):
print(i,end=',')
print('end str test!')
for i in iter(m_set):
print(i,end=',')
print('end set test!')
for i in iter(m_dict):
print(i,end=',')
print('end dict test!')
print('=============next测试================')
my_iter = iter(m_list)
print(next(my_iter))
输出:
=============iter测试================
1,2,3,end list test!
1,2,3,end tuple test!
q,l,e,e,end str test!
1,2,3,end set test!
1,2,end dict test!
=============next测试================
1
class TestIter(object):
def __init__(self):
self.m_list=[1,2,3,4,5,6]
self.it=iter(self.m_list)
def __call__(self):
item = next(self.it)
print ("__call__被调用,此时的next():",item)
return item
def __iter__(self):
print ("__iter__被调用!")
return iter(self.m_list)
t = TestIter() # t是可调用的
print('=============iter()测试================')
new_it = iter(t) #此时可以不用定义__call__
print('=============iter(t,2)测试================')
new_it = iter(t, 2) # t必须是callable的,否则无法返回callable_iterator
print(callable(t))
for i in new_it:
print(i) #每次调用__call__()
print('=============next()测试================')
new_it = iter(t)
print(next(new_it))
print('=============for循环测试================')
#for循环
new_it = iter(t)
for i in new_it:
print(i)
输出:
=============iter()测试================
__iter__被调用!
=============iter(t,2)测试================
True
__call__被调用,此时的next(): 1
1
__call__被调用,此时的next(): 2
=============next()测试================
__iter__被调用!
1
=============for循环测试================
__iter__被调用!
1
2
3
4
5
6
其实在之前的文章中有介绍过该方法,它是一种可以把对象当做像字典一样取值,同时还可以使用for循环调用__getitem__
方法。
第一节提到了,如果使用__getitem__
方法,也可以使用iter函数,同时,执行next()方法时,__getitem__会被执行
。下面分别举例介绍。
class DataTest():
def __init__(self,num):
self.num=num
def __getitem__(self,index):
if(index < self.num):
return "getitem index :" + str(index) + "号"
else:
raise StopIteration
data=DataTest(3)
print('=============for循环测试================')
new_it = iter(data)
#每次执行一次for循环,就调用一次__getitem__
for i in data:
print(i)
print('=============类似字典取值================')
#取0,取一次值,则调用一次__getitem__
print(data[1])
# print(data[5]) #StopIteration,超过索引范围
print('=============iter+next测试================')
new_iter = iter(data)
print(next(new_iter))
输出:
=============for循环测试================
getitem index :0号
getitem index :1号
getitem index :2号
=============类似字典取值================
getitem index :1号
=============iter+next测试================
getitem index :0号
可在类定义中,手动实现__iter__和__next__
方法,如下举例所示。
class DataTest():
def __init__(self,num):
self.num = num
self.start_num = -1
def __iter__(self):
print('__iter__被调用')
return self
def __next__(self):
print('__next__被调用')
self.start_num +=1
if(self.start_num >= self.num):
raise StopIteration()
return self.start_num
data = DataTest(2) #迭代2次
print('=============for循环测试================')
for i in data:
print(i)
print('=============next测试================')
data = DataTest(2) #迭代2次
new_iter = iter(data)
print(next(new_iter))
输出:
=============for循环测试================
__iter__被调用
__next__被调用
0
__next__被调用
1
__next__被调用
=============next测试================
__iter__被调用
__next__被调用
0
__getitem__和__next__
都可以的实现方法都可以使用for操作,但是当两个都实现的情况下,__next__
优先级相对会更高。
# 实验2 循环遍历next,循环遍历中next的优先级高于索引:
class DataTest():
def __init__(self,num):
self.num=num
self.cnt=0
def __getitem__(self,index):
if(index<self.num):
return "getitem 被调用:" + str(index) + "号"
else:
raise StopIteration
def __iter__(self):
print('iter被调用')
self.cnt=0
return self
def __next__(self):
if(self.cnt<self.num):
self.cnt+=1
return "next被调用:" + str(self.cnt) + "号"
else:
print("next结束*********************")
raise StopIteration
data=DataTest(3)
print('=============next举例================')
#next优先级高,所以执行next
it1 = iter(data)
print(next(it1))
print('=============索引举例================')
#索引,调用__getitem__
print(data[1])
print('=============for循环举例================')
#实现__getitem__和__next__都可以实现使用for操作,但是__next__优先级更高
for i in data:
print(i)
print("遍历结束")
输出:
=============next举例================
iter被调用
next被调用:1号
=============索引举例================
getitem 被调用:1号
=============for循环举例================
iter被调用
next被调用:1号
next被调用:2号
next被调用:3号
next结束*********************
遍历结束