第八章:Python高级编程-迭代器和生成器
Python3高级核心技术97讲 笔记
目录
- 第八章:Python高级编程-迭代器和生成器
- 8.1 Python中的迭代协议
- 8.2 什么是迭代器和可迭代对象
- 8.3 生成器函数的使用
- 8.4 Python是如何实现生成器的?
- 8.5 生成器在UserList中的应用
- 8.6 生成器如何读取大文件
8.1 Python中的迭代协议
"""
什么是迭代协议
迭代器是什么? 迭代器是访问集合内元素的一种方式, 一般用来遍历数据
迭代器和以下标的访问方式不一样, 迭代器是不能返回的, 迭代器提供了一种惰性方式数据的方式
[] list , __iter__ __next__
"""
class Iterable(metaclass=ABCMeta):
__slots__ = ()
@abstractmethod
def __iter__(self):
while False:
yield None
@classmethod
def __subclasshook__(cls, C):
if cls is Iterable:
return _check_methods(C, "__iter__")
return NotImplemented
class Iterator(Iterable):
__slots__ = ()
@abstractmethod
def __next__(self):
'Return the next item from the iterator. When exhausted, raise StopIteration'
raise StopIteration
def __iter__(self):
return self
@classmethod
def __subclasshook__(cls, C):
if cls is Iterator:
return _check_methods(C, '__iter__', '__next__')
return NotImplemented
8.2 什么是迭代器和可迭代对象
from collections.abc import Iterator
class Company(object):
def __init__(self, employee_list):
self.employee = employee_list
def __iter__(self):
return MyIterator(self.employee)
# def __getitem__(self, item):
# return self.employee[item]
class MyIterator(Iterator):
def __init__(self, employee_list):
self.iter_list = employee_list
self.index = 0
def __next__(self):
#真正返回迭代值的逻辑
try:
word = self.iter_list[self.index]
except IndexError:
raise StopIteration
self.index += 1
return word
if __name__ == "__main__":
company = Company(["tom", "bob", "jane"])
my_itor = iter(company)
# while True:
# try:
# print (next(my_itor))
# except StopIteration:
# pass
# next(my_itor)
for item in company: # 执行了iter(company)
print (item)
8.3 生成器函数的使用
# 生成器函数,函数里只要有yield关键字
# 惰性求值,延迟求值提供了可能
def gen_func(): # 返回的是一个生成器对象,在Python编译字节码是产生
yield 1
yield 2
yield 3
def fib(index):
if index <= 2:
return 1
else:
return fib(index-1) + fib(index-2)
def fib2(index):
re_list = []
n,a,b = 0,0,1
while n
8.4 Python是如何实现生成器的?
#1.python中函数的工作原理
"""
"""
import inspect
frame = None
def foo():
bar()
def bar():
global frame
frame = inspect.currentframe()
#python.exe会用一个叫做 PyEval_EvalFramEx(c函数)去执行foo函数, 首先会创建一个栈帧(stack frame)
"""
python一切皆对象,栈帧对象, 字节码对象
当foo调用子函数 bar, 又会创建一个栈帧
所有的栈帧都是分配在堆内存(不会立即释放)上,这就决定了栈帧可以独立于调用者存在
"""
# import dis
# print(dis.dis(foo))
foo()
print(frame.f_code.co_name)
caller_frame = frame.f_back
print(caller_frame.f_code.co_name)
def gen_func():
yield 1
name = "bobby"
yield 2
age = 30
return "imooc"
import dis
gen = gen_func()
print (dis.dis(gen))
print(gen.gi_frame.f_lasti)
print(gen.gi_frame.f_locals)
next(gen)
print(gen.gi_frame.f_lasti)
print(gen.gi_frame.f_locals)
next(gen)
print(gen.gi_frame.f_lasti)
print(gen.gi_frame.f_locals)
8.5 生成器在UserList中的应用
class company:
def __getitem__(self, item):
pass
from collections import UserList # 不要用继承list,因为是c写的
def __iter__(self):
i = 0
try:
while True:
v = self[i]
yield v
i += 1
except IndexError:
return
8.6 生成器如何读取大文件
#500G, 特殊 一行
def myreadlines(f, newline):
buf = ""
while True:
while newline in buf:
pos = buf.index(newline)
yield buf[:pos]
buf = buf[pos + len(newline):]
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)