一、概念及关系
1、概念
可迭代对象:实现__iter__方法的类的实例对象。
迭代器:实现__iter__和__next__方法的类的实例对象,两个方法缺一不可。
生成器:调用含有yield关键字的函数会返回一个生成器对象。
2、关系
迭代器一定是可迭代对象,可迭代对象不一定是迭代器。
生成器是一种特殊的迭代器。
二、示例
1、可迭代对象
字符串对象、列表对象、字典对象、元组对象、集合对象都是可迭代对象,但不是迭代器。因为它们都内置实现了__iter__。
from collections import Iterator, Iterable
str_test = "zhangsan"
list_test = ["zhangsan", "lisi", "wangwu"]
dict_test = {"name0": "zhangsan", "name1": "lisi", "name2": "wangwu"}
tuple_test = ("zhangsan", "lisi", "wangwu")
set_test = {"zhangsan", "lisi", "wangwu"}
print(isinstance(str_test, Iterable))
print(isinstance(str_test, Iterator))
print(isinstance(list_test, Iterable))
print(isinstance(list_test, Iterator))
print(isinstance(dict_test, Iterable))
print(isinstance(dict_test, Iterator))
print(isinstance(tuple_test, Iterable))
print(isinstance(tuple_test, Iterator))
print(isinstance(set_test, Iterable))
print(isinstance(set_test, Iterator))
"""
运行结果:
True
False
True
False
True
False
True
False
True
False
Process finished with exit code 0
"""
2、迭代器
(1) iter、__next__自定义迭代器
class Students:
def __init__(self, names):
self.names = names
self.counter = -1
def __iter__(self):
print("+++__iter__+++")
return self
def __next__(self):
self.counter += 1
if self.counter >= len(self.names):
raise StopIteration
return self.names[self.counter]
if __name__ == '__main__':
names = ["zhangsan", "lisi", "wangwu"]
students = Students(["zhangsan", "lisi", "wangwu"])
for name in students:
print(name)
"""
for...in..过程等同于以下过程
iter(students) # 当使用while运行迭代器时可以去掉这条语句,因为students该对象本身就是迭代器,运行结果中也不会有第一行+++__iter__+++
while True:
try:
print(next(students))
except StopIteration as e:
break
"""
from collections import Iterable, Iterator
print(isinstance(students, Iterator))
print(isinstance(students, Iterable))
"""
运行结果:
+++__iter__+++
zhangsan
lisi
wangwu
True
True
Process finished with exit code 0
"""
自定义迭代器需注意三点:
- 必须实现__iter__()方法
- 必须实现__next__()方法
- 在__next__()方法中当最后一个元素被迭代出后抛出StopIteration异常
(2)将绑定__getitem__方法的实例对象通过iter转变为迭代器
__getitem__:如果类把某个属性定义为序列,可以使用__getitem__输出序列属性中的某个元素。可以认为绑定__getitem__方法的实例对象为自定义序列对象。
(3) 将序列转化为迭代器
# 以列表为例
list_test = ["zhangsan", "lisi", "wangwu", "zhaoliu"]
list_test = iter(list_test)
while True:
try:
print(next(list_test))
except StopIteration as e:
break
"""
运行结果:
zhangsan
lisi
wangwu
zhaoliu
Process finished with exit code 0
"""
# 以字典为例
dict_test = {"name0": "zhangsan", "name1": "lisi", "name2": "wangwu", "name3": "zhaoliu"}
dict_test = iter(dict_test)
while True:
try:
print(next(dict_test))
except StopIteration as e:
break
"""
运行结果:
name0
name1
name2
name3
Process finished with exit code 0
"""
3、生成器
def Test(tests):
for test in tests:
yield test
if __name__ == '__main__':
list_test = ["zhangsan", "lisi", "wangwu", "zhaoliu"]
test_gen = Test(list_test)
for test in test_gen:
print(test)
"""
运行结果:
zhangsan
lisi
wangwu
zhaoliu
Process finished with exit code 0
"""
三、辨析__iter__、iter
1、iter
迭代协议:绑定__iter__方法的实例对象称为可迭代对象。
2、iter
以下是 iter方法的语法:
iter(object[, sentinel])
object:支持迭代协议的实例对象或支持序列协议的实例对象,否则会返回TypeError异常。
sentinel:传递了第二个参数时。(i) 参数 object 必须是一个能够对内部状态进行维护可调用的对象(如,闭包内函数对象或绑定的__call__方法的实例对象);(ii) iter 创建了一个迭代器对象,每次调用这个迭代器对象的__next__方法时,都会调用 object;(iii) 当__next__的返回值等于哨兵时,就会抛出异常StopIteration。
【注】序列协议:绑定__getitem__方法的实例对象称为自定义序列对象。
(1)只有第一个参数object出现时
只绑定__iter__方法的实例对象一般结合迭代器使用。
class StudentList(object): # 创建一个类,为了创建对应的可迭代对象
def __init__(self):
self.items = [] # 定义一个属性是空列表
def append(self, name): # 定义方法可以传参数添加到空列表
self.items.append(name)
def __iter__(self): # 定义iter方法,返回的是对应的可迭代器
print("++__iter__++")
return ListIter(self.items)
class ListIter(object): # 自定义迭代器:作用是记录迭代位置和帮助可迭代对象返回数据
def __init__(self, items):
self.items = items # 保存数据
self.index = -1 # 记录下标位置
def __iter__(self):
return self
def __next__(self):
self.index += 1 # 每次使用,下标即+1
if self.index < len(self.items):
return self.items[self.index] # 返回下标数据
else:
raise StopIteration # 抛出异常
if __name__ == '__main__':
my_list = StudentList()
my_list.append("zhangsan")
my_list.append("lisi")
my_list.append("wangwu")
my_list.append("zhaoliu")
for name in my_list:
print(name)
"""
运行结果:
++__iter__++
zhangsan
lisi
wangwu
zhaoliu
Process finished with exit code 0
"""
(2) 第二个参数sentinel出现时
# (i) object为闭包内函数对象时
def function_out(list_):
index = -1
def function_in():
nonlocal index
index += 1
result = list_[index] # 此处可做一些其它操作
return result
return function_in
if __name__ == '__main__':
names = ["zhangsan", "lisi", "wangwu", "zhaoliu"]
students = function_out(names)
for name in iter(students, "wangwu"): # for...in...内部自动会处理StopIteration异常
print(name)
"""
运行结果:
zhangsan
lisi
Process finished with exit code 0
"""
# (2) object为绑定的__call__()方法的实例对象时
class ListIter(object):
def __init__(self, items):
self.items = items
self.index = -1
def __call__(self):
self.index += 1
result = self.items[self.index] # 此处可以做一些其它操作
return result
if __name__ == '__main__':
names = ["zhangsan", "lisi", "wangwu", "zhaoliu"]
students = ListIter(names)
for name in iter(students, "wangwu"):
print(name)
"""
运行结果:
zhangsan
lisi
Process finished with exit code 0
"""
总结:
- 对于函数来说,闭包可以实现内部函数状态的维护。
- 对于对象来说,可以通过属性实现对某个方法的内部状态的维护。