9.1 python的迭代协议


list内部实现了__iter__()协议(魔法函数),是可迭代对象,但还不是迭代器(迭代器需要实现__next__协议)

image

生成器实现了__iter__(),__next__()协议,因此是迭代器。但迭代器不一定是生成器(不具有生成器的方法协议)

image

#什么是迭代协议 #迭代器是什么? 迭代器是访问集合内元素的一种方式, 一般用来遍历数据 #迭代器和以下标的访问方式不一样, 迭代器是不能返回的, 迭代器提供了一种惰性方式数据的方式 #[] list , __iter__ from collections.abc import Iterable, Iterator
a = [1,2]
iter_rator = iter(a) print (isinstance(a, Iterable)) print (isinstance(a, Iterator)) print (isinstance(iter_rator, Iterator))

---
True
False
True


9.2 什么是迭代器和可迭代对象

from collections.abc import Iterator class Company(object): def __init__(self, employee_list):
        self.employee = employee_list def __iter__(self): # 可迭代对象,实现了__iter__ return MyIterator(self.employee) # iter(可迭代对象) 方法 会调用反回迭代器 # def __getitem__(self, item):        # 当没有定义__iter__协议for循环就会将定义的getitem变成迭代器 #     return self.employee[item]      # 退化为迭代器 # 可迭代对象不要去实现__next__ class MyIterator(Iterator): # 迭代器 实现了__next__ 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)

    for item in company: print (item) # --- tom
bob
jane


9.3 生成器函数使用

#生成器函数,函数里只要有yield关键字 def gen_func():
    yield 1
    yield 2
    yield 3 def func(): return 1 if __name__ == "__main__": #生成器对象, python编译字节码的时候就产生了, gen = gen_func() # <generator object gen_func at 0x000001CD083334F8> print(gen)
    for value in gen: print (value) # --- <generator object gen_func at 0x000001CD08333570>
1
2
3 # --- 
 
 
# 斐波拉契 0 1 1 2 3 5 8 # 惰性求值, 延迟求值提供了可能 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<index:
        re_list.append(b)
        a,b = b, a+b
        n += 1 return re_list print(fib(10)) print(fib2(10)) # --- 55
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55] # --- def gen_fib(index):
    n,a,b = 0,0,1
    while n<index:
        yield b
        a,b = b, a+b
        n += 1

for data in gen_fib(10): print (data) # --- 1
1
2
3
5
8
13
21
34
55


9.4 生成器的原理

#1.python中函数的工作原理 def foo():
    bar() def bar():
    pass #python.exe会用一个叫做 PyEval_EvalFramEx(c函数)去执行foo函数, 首先会创建一个栈帧(stack frame) """
python一切皆对象,栈帧对象, 字节码对象
当foo调用子函数 bar, 又会创建一个栈帧
所有的栈帧都是分配在堆内存上,这就决定了栈帧可以独立于调用者存在
""" import dis print(dis.dis(foo)) #--- 5           0 LOAD_GLOBAL              0 (bar)
              2 CALL_FUNCTION            0
              4 POP_TOP
              6 LOAD_CONST               0 (None)
              8 RETURN_VALUE
None #---  import inspect frame = None def foo():
    bar() def bar():
    global frame
    frame = inspect.currentframe()

foo() print(frame.f_code.co_name) #栈针 caller_frame = frame.f_back # 调用他的栈针 print(caller_frame.f_code.co_name) # --- bar
foo


image

image

def gen_func():
    yield 1 name = "lewen"
    yield 2
    age = 30 return "imooc" import dis
gen = gen_func() print (dis.dis(gen)) # --- 2           0 LOAD_CONST               1 (1)
              2 YIELD_VALUE
              4 POP_TOP

  3           6 LOAD_CONST               2 ('lewen')
              8 STORE_FAST               0 (name)

  4          10 LOAD_CONST               3 (2)
             12 YIELD_VALUE
             14 POP_TOP

  5          16 LOAD_CONST               4 (30)
             18 STORE_FAST               1 (age)

  6          20 LOAD_CONST               5 ('imooc')
             22 RETURN_VALUE
None # --- 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) # --- -1
{}
2
{}
12
{'name': 'lewen'}


9.5 通过UserList来看生成器的应用


from collections import UserList # 用Python实现的list


image

9.6 生成器实现大文件读取

# 500G, 特殊 全部在 一行,由特殊分割符分割
# 一次性读取太大,按分隔符读取 def myreadlines(f, newline):
    buf = "" # 缓存 while True:
        while newline in buf: pos = buf.index(newline)
            yield buf[:pos] # 将第一个分隔符之前的数据yield 出去 buf = buf[pos + len(newline):] # 丢弃掉yield的数据,如果buf中还有分隔符就继续处理, chunk = f.read(4096) # 没有就继续读新的4096个字节 if not chunk: # 说明已经读到了文件结尾 yield buf
            break
        buf += chunk


with open("input.txt") as f:
    for line in myreadlines(f, "{|}"): print(line)



image


点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信小程序

微信扫一扫体验

立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部