@[toc]
1. 迭代器
我们以后不会自己去写迭代器,只要学会使用迭代器就可以了。
1.1 迭代器的作用
如果有这样的需求,展示列表中的所有数据。
实现方法:① while+索引+计数器;② 迭代器
迭代器:对可迭代对象(序列类型,如str/list/tuple/dict/set)中的元素进行逐一获取。表象:具有next方法且每次调用都获取可迭代对象中的元素(从前到后一个一个获取)。
1.2 迭代器的使用
① 列表转换成迭代器方法一:v = [1, 2, 3, 4, 5, 6],val = iter(v)(使用内置函数iter)
# coding:utf-8
v = iter([1, 2, 3, 4, 5, 6])
print(v, type(v))
'''
'''
② 列表转换成迭代器方法二:v = [1, 2, 3, 4, 5, 6],val = v.__ iter__ ()(使用__ iter__ 方法)
# coding:utf-8
v = [1, 2, 3, 4, 5, 6]
# val = iter(v)#内部会调用__iter__方法
v2 = v.__iter__()
while True:
val = v2.__next__()
print(val)
③ 迭代器获取每个值:反复调用val.__ next __()(val是迭代器对象)
# coding:utf-8
v = iter([1, 2, 3, 4, 5, 6])
val1 = v.__next__()
val2 = v.__next__()
val3 = v.__next__()
val4 = v.__next__()
val5 = v.__next__()
val6 = v.__next__()
print(val1, val2, val3, val4, val5, val6)
'''
1 2 3 4 5 6
'''
# coding:utf-8
v = iter([1, 2, 3, 4, 5, 6])
while True:
try:
val = v.__next__()
print(val)
except Exception as e:
break
④ 直到报错:StopIteration错误
# coding:utf-8
v = iter([1, 2, 3, 4, 5, 6])
while True:
val = v.__next__()
print(val)
'''
1
2
3
4
5
6
StopIteration
'''
1.3 for循环与迭代器
for循环的内部使用的是迭代器:
# coding:utf-8
v = ['thanlon', 'kiku']
'''
1. for循环内部会将v1转换成迭代器
2. 内部反复执行“迭代器.__next__()”方法,一个个取值
3. 取完值不报错
'''
for item in v:
print(item)
'''
thanlon
kiku
'''
1.4 可迭代对象
① 可以被for循环且对象中具有iter()方法,还要返回一个迭代器(或生成器),
v = [1, 2, 3]
result = v.__iter__() # 有__iter__方法,且返回迭代器对象(result),所以v是迭代器对象
print(result) # result =
② 可以被for循环
1.5 可迭代对象与迭代器之间关系
可迭代对象可以转换成迭代器。
2. 生成器
2.1 生成器函数
① 函数:
def func():
return 'thanlon'
func()
② 生成器函数
如何判断是生成器函数:内部是否包含yield
# 生成器函数(内部是否包含yield)
def func():
print('f1')
yield 1
print('f2')
print('f2')
yield 2
print('f3')
print('f3')
print('f3')
yield 3
print('f4')
print('f4')
print('f4')
print('f4')
print('f4')
# 函数内部代码不会被执行,返回一个生成器对象
v = func()
print(v, type(v))
'''
'''
生成器是可以被for循环的,一旦开始循环内部代码就会开始执行:
# 生成器函数(内部是否包含yield)
def func():
print('f1')
yield 1
print('f2')
print('f2')
yield 2
print('f3')
print('f3')
print('f3')
yield 3
print('f4')
print('f4')
print('f4')
print('f4')
print('f4')
v = func()
for item in v:
print(item)
'''
f1
1
f2
f2
2
f3
f3
f3
3
f4
f4
f4
f4
f4
'''
2.2 yield from
从当前生成器跳到另一个生成器。
# coding:utf-8
def func():
yield 3
yield 4
def func2():
yield 1
yield 2
yield from func()
yield 5
result = func2()
for item in result:
print(item)
# coding:utf-8
def func():
return 3
def func2():
yield 1
yield 2
yield from func()
yield 5
result = func2()
for item in result:
print(item)
'''
TypeError: 'int' object is not iterable
'''
# coding:utf-8
# 使用可迭代的列表类型
def func():
return [3, 4]
def func2():
yield 1
yield 2
yield func()
yield 5
result = func2()
for item in result:
print(item)
'''
1
2
[3, 4]
5
'''
# coding:utf-8
def func():
return [3, 4]
def func2():
yield 1
yield 2
# yield func() # 把[3, 4]当作整体拿过来
yield from func() # 把[3,4]拆开拿过来
yield 5
result = func2()
for item in result:
print(item)
'''
1
2
3
4
5
'''
2.3 生成器例子
# coding:utf-8
def func():
return 1
if 1 != 1:
yield 2
yield 3
v = func()
print(v, type(v))
'''
'''
# coding:utf-8
def func():
while True:
yield 1
val = func()
print(val) #
for item in val:
print(item)
# coding:utf-8
def func():
count = 1
while True:
yield count
count += 1
val = func()
print(val)
for item in val:
print(item)
# coding:utf-8
def func():
return 1
yield 2
yield 3
val = func()
for item in val:
print(item) # 由于return的作用,无内容
# coding:utf-8
def func():
yield 2
return 111
yield 3
val = func()
for item in val:
print(item)
'''
2
'''
# coding:utf-8
def func():
count = 1
while True:
yield count
count += 1
if count == 101:
return
val = func()
for item in val:
print(item)
'''
打印1~100
'''
2.4 生成器总结
函数中如果存在yield(注意与return无关),那么这个函数就是一个生成器函数。调用一个生成器函数会返回一个生成器对象,生成器只有被for循环时,生成器函数内部的代码才会被执行,生成器每次循环都会获取yield返回的值。
2.5 生成器应用示例
① 读取文件案例:分批读取文件,将文件的内容返回给调用者
# coding:utf-8
def func():
cursor = 0
while True:
f = open('log.txt', 'r', encoding='utf-8')
f.seek(cursor)
data_list = []
for i in range(5): # 每次读5条
line = f.readline()
if not line:
return
data_list.append(line)
cursor = f.tell() # 获取当前游标位置
f.close()
for row in data_list:
yield row
for item in func():
print(item)
② redis源码示例:
安装第三方模块Redis:pip install redis
import redis
conn = redis.Redis(host='……')
# scan_iter()是一个生成器函数
conn.scan_iter()
def scan_iter(self, match=None, count=None):
"""
Make an iterator using the SCAN command so that the client doesn't
need to remember the cursor position.
``match`` allows for filtering the keys by pattern
``count`` allows for hint the minimum number of returns
"""
cursor = '0'
while cursor != 0:
# 每次取100条数据
# cursor:取完之后的游标位置
# data:本次取出来的100条数据
cursor, data = self.scan(cursor=cursor, match=match, count=count)
for item in data:
yield item
2.6 生成器补充
① 生成器的两个作用:
- 生成数据
- 迭代
② 生成器是特殊的迭代器
生成器有next方法:
# coding:utf-8
def func():
yield 1
yield 2
yield 3
v = func() # v是生成器(对象)
# print(v, type(v)) #
# print(dir(v)) # 查看生成器v中都有哪些方法,dir(v)返回列表
for i in dir(v):
print(i)
'''
__class__
__del__
__delattr__
__dir__
__doc__
__eq__
__format__
__ge__
__getattribute__
__gt__
__hash__
__init__
__init_subclass__
__iter__
__le__
__lt__
__name__
__ne__
__new__
__next__
__qualname__
__reduce__
__reduce_ex__
__repr__
__setattr__
__sizeof__
__str__
__subclasshook__
close
gi_code
gi_frame
gi_running
gi_yieldfrom
send
throw
'''
且每次调用都获取生成器对象中的元素:
# coding:utf-8
def func():
yield 1
yield 2
yield 3
v = func() # v是生成器(对象),也是特殊的迭代器对象
result = v.__next__()
print(result)
result = v.__next__()
print(result)
result = v.__next__()
print(result)
'''
1
2
3
'''
③ 生成器是特殊的可迭代对象:生成器中有iter方法
# coding:utf-8
'''
把v当做可迭代对象
'''
def func():
yield 1
yield 2
yield 3
v = func()
result = v.__iter__()
print(result)
''''''
如果一个对象有iter()方法且返回一个迭代器称这个对象是可迭代对象。如果一个对象,它有iter()方法,它返回一个生成器,它也是可迭代对象。