gj9 迭代器和生成器

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
  

 

posted @ 2019-02-13 00:03  元贞  阅读(297)  评论(0编辑  收藏  举报