1. 可迭代对象
可以转换为不依赖索引取值的容器,通过__ iter __()方法生成迭代器对象
列表、字典、集合、字符串、元组,这类容器都是可迭代对象
2. 迭代器对象
迭代器对象也是可迭代对象,也有__ iter __ ()方法,会返回迭代器对象自身
可以通过__ next __() 方法进行取值
# 定义不同的容器,他们都是可迭代对象,也是迭代器对象
test_dict = {1: 'a', 2: 'b', 3: 'd'}
test_list = [100, 200, 300, 400]
test_set = {21, 22, 23, 24}
# 可迭代对象,通过__iter__()方法获得对应的迭代器对象
# 迭代器对象,使用__iter__()方法返回自身
iter_list = test_list.__iter__()
iter_dict = test_dict.__iter__()
iter_set = test_set.__iter__()
print(iter_list)
print(iter_dict)
print(iter_set)
print()
# 可迭代对象调用__iter__()方法,会返回自身
print(iter_list.__iter__())
print(iter_dict.__iter__())
print(iter_set.__iter__())
执行结果:
<list_iterator object at 0x0000025BA6C1E9C8>
<dict_keyiterator object at 0x0000025BA6B55BD8>
<set_iterator object at 0x0000025BA6C143B8><list_iterator object at 0x0000025BA6C1E9C8>
<dict_keyiterator object at 0x0000025BA6B55BD8>
<set_iterator object at 0x0000025BA6C143B8>
迭代器对象没有长度,不能使用len()函数
test_dict = {1: 'a', 2: 'b', 3: 'd'}
test_list = [100, 200, 300, 400]
test_set = {21, 22, 23, 24}
# 迭代器对象取值:
# 1. 顺序:按照名称空间的顺序取值
# 2. 容器:取一个少一个'''
print('list:%d' % iter_list.__next__())
print('dict:%d' % iter_dict.__next__())
# set没有取值顺序
print('set:%d' % iter_set.__next__())
new_list = iter_list.__iter__()
print('list:%d' % new_list.__next__())
# 字典的__next__()方法取到的是key
new_dict = iter_dict.__iter__()
print('dict:%d' % new_dict.__next__())
new_set = iter_set.__iter__()
print('set:%d ' % new_set.__next__())
执行结果:
list:100 dict:1 set:24
list:200 dict:2 set:21
迭代器对象取值没有尽头,在迭代器对象中没有元素时,会抛出StopIteration异常
while True:
try:
print(iter_list.__next__())
except StopIteration:
break
常见的迭代器对象有:enumerate()、file、生成器对象
3. 迭代器
即for循环,是用来从可迭代对象或迭代器对象中取值的方法
通过对象.__ iter ()方法获取容器对象的迭代器对象,在将_ next __() 方法获得的值赋值给 变量
当迭代器对象取完了,内部自动捕获异常,并结束循环
# 这里可以省略掉对象.__iter__()的写法,for语句内部已经对可迭代对象执行了__iter__()
for i in test_set.__iter__():
print('iterator item: ', i)
with open('test','r',encoding='utf-8') as test_file:
print(test_file)
print(test_file.__next__())
4. 生成器
可以自定义的迭代器
生成器对象也是迭代器对象,因此可以通过__ next __()方法或者for语句迭代访问元素
# 迭代器方法中不用return,可多次使用yield依次返回值
def fn():
print('step1')
yield 1000
print('step2')
yield 2000
# 生成器对象也是迭代器对象,因此可以通过__next__()方法访问
f = fn()
print(f)
print(f.__next__())
print(f.__next__())
# for循环语句访问对生成器对象
for i in fn():
print(i)
执行结果:
<generator object fn at 0x000001C1E0A8ECC8>
step1
1000
step2
2000
step1
1000
step2
2000
生成器方法可以传入参数,可以传入可变参数,对任意长度的参数迭代返回结果
# 定义生成器,对传入参数double返回
def fn1(*args):
i = 0
# 可变参数args是一个容器
while i < len(args):
yield args[i] * 2
i += 1
for i in fn1(1, 23, 42, 142):
print(i)
执行结果:
2,46,84,284,
注意观察生成器中的yield语句,每次迭代,生成器会返回yield语句的结果,之后从yield语句处继续下一次迭代
# 定义生成器,可以无限生成自然数的阶乘
def fn2():
total = 1
count = 1
while True:
total *= count
# 每次遇到yield语句就返回,但是后面的语句会接着执行
yield total
count += 1
f2 = fn2()
print(f2.__next__())
print(f2.__next__())
print(f2.__next__())
print(f2.__next__())
执行结果:
1
2
6
24
生成器对象的send方法配合yield语句使用:
a) 为当前停止的yield传入参数,供下一次逻辑使用
b) 自身也会调用__ next __()获取下一个yield的结果
def fn3():
msg = yield 501
print(msg)
yield 502
yield 503
f3 = fn3()
print(f3.__next__())
# 默认的send参数是None,注意不能在生成器第一次返回的时候send方法,因为此时生成器还没有走到任何yield语句
res = f3.send('send me')
print(res)
print(f3.__next__())
执行结果:
501
send me
502
503
# 生成器对象的send方法示例
def fn4(namelist):
count = 0
print('%s在面试' % namelist[count])
while count < len(namelist):
name = yield namelist[count]
count += 1
print(name + '叫%s来面试' % namelist[count])
name_list = ['Amy', 'Bob', 'Christain', 'David']
f4 = fn4(name_list)
name = f4.send(None)
print(name + '面试完毕')
while True:
try:
name = f4.send(name)
print(name + '面试完毕')
except Exception:
print('所有人面试完毕')
break
执行结果:
Amy在面试
Amy面试完毕
Amy叫Bob来面试
Bob面试完毕
Bob叫Christain来面试
Christain面试完毕
Christain叫David来面试
David面试完毕
所有人面试完毕
课后小练:
# 自定义一个range
class myrange():
def __init__(self, start, end):
self.start = start
self.end = end
# range是迭代器,所以要定义__iter__方法。并返回自身
def __iter__(self):
return self
# 定义迭代器的__next__方法
def __next__(self):
if self.start < self.end:
self.start += 1
return self.start - 1
else:
raise StopIteration
for i in myrange(1, 3):
print(i)