第八章:Python高级编程-迭代器和生成器

第八章: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<index:
        re_list.append(b)
        a,b = b, a+b
        n += 1
    return re_list


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)
# print (gen_fib(10))
# 斐波拉契 0 1 1 2 3 5 8
#惰性求值, 延迟求值提供了可能

def func():
    return 1


if __name__ == "__main__":
    #生成器对象, python编译字节码的时候就产生了,
    gen = gen_func()
    for value in gen:
        print (value)
    # re = func()
    # pass

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)
posted @ 2020-08-16 13:07  公众号海哥python  阅读(112)  评论(0编辑  收藏  举报