先看一个这样的示例
class Company:
def __init__(self,users):
self.users = users
self.index = 0
def __getitem__(self, item):
return self.users[item]
if __name__ == "__main__":
c = Company(["小明", "小红", "小刚"])
for u in c:
print(u)
这样原来的实例就可以遍历了,__getitem__
有个参数item
就是迭代的索引,这是因为编译器自动在内部自动生成了迭代器,相当于如下代码
from collections.abc import Iterator
class Company:
def __init__(self, users):
self.users = users
self.index = 0
def __iter__(self):
return MyIterator(self.users)
class MyIterator(Iterator):
def __init__(self, list):
self.index = 0
self.list = list
def __next__(self):
try:
item = self.list[self.index]
self.index += 1
except IndexError:
raise StopIteration
return item
if __name__ == "__main__":
c = Company(["小明", "小红", "小刚"])
for u in c:
print(u)
但是我们明明抛出异常了,但是并没有捕获处理啊!这是因为for in
内部已经处理了
for in
相当于转化为了如下代码:
class Company:
def __init__(self, users):
self.users = users
self.index = 0
def __getitem__(self, item):
return self.users[item]
if __name__ == "__main__":
c = Company(["小明", "小红", "小刚"])
my_itor = iter(c)
while True:
try:
item = next(my_itor)
print(item)
except StopIteration:
pass
只要方法中有yield
,就会被解析为生成器
import dis
def gen_func():
name = "小红"
yield name
name = "小明"
yield name
name = "小刚"
if __name__ == "__main__":
g = gen_func()
dis.dis(g)
print("-----------------")
print(g.gi_frame.f_lasti)
print(g.gi_frame.f_locals)
print("-----------------")
print(next(g))
print(g.gi_frame.f_lasti)
print(g.gi_frame.f_locals)
print("-----------------")
print(next(g))
其中
g = gen_func()
获取生成器对象dis.dis(g)
能查看生成器对象的字节码执行过程g.gi_frame.f_lasti
能查看字节码执行的行号g.gi_frame.f_locals
能查看当时的环境变量
结果
3 0 LOAD_CONST 1 ('小红')
2 STORE_FAST 0 (name)
4 4 LOAD_FAST 0 (name)
6 YIELD_VALUE
8 POP_TOP
5 10 LOAD_CONST 2 ('小明')
12 STORE_FAST 0 (name)
6 14 LOAD_FAST 0 (name)
16 YIELD_VALUE
18 POP_TOP
7 20 LOAD_CONST 3 ('小刚')
22 STORE_FAST 0 (name)
24 LOAD_CONST 0 (None)
26 RETURN_VALUE
-----------------
-1
{}
-----------------
小红
6
{'name': '小红'}
-----------------
小明
我们可以用for来遍历生成器的结果
def gen_func():
name = "小红"
yield name
name = "小明"
yield name
name = "小刚"
return name
if __name__ == "__main__":
g = gen_func()
for item in g:
print(item)
结果
小红
小明
可以看出我们只能接收yield返回的值
读取多行文件
aaaaaa
bbb
ccc
dd
读取
with open("input.txt") as f:
for line in f.readlines():
print("line:" + line)
读取单行大文件
假如文件只有一行,并且文件较大,有固定的分隔符
aaaaaa[|]bbb[|]ccc[|]dd
读取代码
def myreadlines(f, separator):
buf = ""
while True:
while separator in buf:
pos = buf.index(separator)
yield buf[:pos]
buf = buf[pos + len(separator):]
chunk = f.read(4096)
if not chunk:
yield buf
break
buf += chunk
with open("input.txt") as f:
for line in myreadlines(f, "[|]"):
print("line:" + line)