python迭代器和生成器

python迭代协议

1.迭代协议: 可迭代类型 Iterable 迭代器iterator

2.什么是迭代器:
迭代器是用来访问集合内元素的一种方式,一般用来遍历数据
迭代器和下标的访问方式不一样,迭代器是不能返回的,迭代器提供了一种惰性数据的方式
[] list , __ iter __

#from _collections_abc import Iterator,Iterable
from collections.abc import Iterator,Iterable
#list
a=[1,2,3,4]
print(isinstance(a,Iterable)) #True
print(isinstance(a,Iterator)) #False
#如果list实现了iter()并且返回了Iterator1迭代器,
#那么Iterator就是一个迭代器
Iterator1=iter(a)
print(isinstance(Iterator1,Iterator))#True

源码:
Iterable:


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


Iterator:


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

自定义迭代器

下面这段代码是将类的对象变为可迭代对象,然后通过iter(实例化对象)
返回一个迭代器。

class Company(object):
    def __init__(self,employee_list):
        self.employee=employee_list
    '''
    如果函数中_iter_和__getitem__都没有实现,
    则在使用iterator=iter(类的实例化对象)会报出错误
    '''
    def __iter__(self):
        return iter(self.employee)
    # def __getitem__(self, item):
    #     return self.employee[item]
if __name__=="__main__":
     company=Company(["xiaopang","xiaohe","like"])
     my_itor=iter(company)
     for   item in company:
         print(item)
 

自定义迭代器:


class Company(object):
    def __init__(self,employee_list):
        self.employee=employee_list
    '''
    如果函数中_iter_和__getitem__都没有实现,
    则在使用iterator=iter(类的实例化对象)会报出错误
    '''
    def __iter__(self):
        return MyIterator(self.employee)


from collections.abc import Iterator
class MyIterator:   #迭代器是在需要的使用
    def __init__(self,employee_list):
        self.iter_list=employee_list
        #维护内部的一个变量
        self.index=0
    #__iter__在这个自定义的迭代器中可不用实现
    # def __iter__(self):
    #     return self

    def __next__(self):
        #真正返回迭代值的逻辑
        try:
             word=self.iter_list[self.index]
        except  IndexError:
             raise  StopIteration
        self.index+=1
        return word

if __name__=="__main__":
     company=Company(["xiaopang","xiaohe","like"])
     my_itor=iter(company)
     # for   item in company:
     #     print(item)
     while True:
         try:
             print(next(my_itor))
         except StopIteration:
             pass

     pass

生成器函数的使用

#生成器函数  函数里只要存在  yield关键字
def  gen_func():
    yield 1
    #返回的是一个生成器对象,生成器对象是在python
    #编译字节码的时候就产生了
    yield 2
    yield 3
#传统做法
def   fib(index):
    if index<=2:
        return 1
    else :
        return fib(index-1)+fib(index-2)
print(fib(10))


def  fib1(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(fib1(10))
#斐波那契    0 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
print("...........生成器..........")
for   data  in gen_fib(10):
      print(data)

print(".......................")
def func():
    return 1
if __name__=="__main__":
    gen=gen_func()
    #生成器对象也是实现了我们的迭代器协议的
    for value in gen:
        print(value)
    re=func()
    pass

生成器原理

1.python函数运行原理:


#python在运行之前会编译,变异成字节码文件
#python中函数的工作原理


import inspect
frame=None
def  foo():
    bar()

def bar():
  global   frame
  frame=inspect.currentframe()


# python解释器python.exe使用c语言来写的,解释器会用
#一个叫做PyEval_EvalFramEx() 的c语言函数去执行python
#函数foo,首先会创建一个栈帧(stack frame)
"""
python中一切皆对象,栈帧是一个对象,会将python中的对象
变为字节码对象  当foo调用子函数bar,又会创建一个栈帧,并将
解释器的控制权交给这个栈帧对象,然后将bar变为字节码对象


所有的栈帧都是分配在堆内存上,堆内存如果不去释放它,它
就会一直存放在堆内存当中,这就决定了栈帧可以独立于调用
者存在

"""
# import  dis
# #查看函数foo的字节码
# print(dis.dis(foo))

'''
查看foo函数的字节码过程:
  6           0 LOAD_GLOBAL              0 (bar)
              2 CALL_FUNCTION            0
              4 POP_TOP
              6 LOAD_CONST               0 (None)
              8 RETURN_VALUE
None
'''
foo()
# 这个函数调用完之后我们依然可以拿到它的栈帧
print(frame.f_code.co_name) #bar
#可以拿到调用bar的栈帧
caller_frame=frame.f_back
print(caller_frame.f_code.co_name)#foo

在这里插入图片描述
在这里插入图片描述
2.生成器

生成器像上述一样运行在堆内存当中,并且独立于调用者存在,完成了对函数整个运行过程的控制。yield生成器对象可以让函数暂停,并访问到f_lasti和f_locals。



def  gen_fun():
    yield 1
    name="xiaopang"
    yield 2
    age =23
    return "eater"
import dis
gen=gen_fun()   #生成器运行在堆内存中
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)


'''
 53           0 LOAD_CONST               1 (1)
              2 YIELD_VALUE
              4 POP_TOP

 54           6 LOAD_CONST               2 ('xiaopang')
              8 STORE_FAST               0 (name)

 55          10 LOAD_CONST               3 (2)
             12 YIELD_VALUE
             14 POP_TOP

 56          16 LOAD_CONST               4 (23)
             18 STORE_FAST               1 (age)

 57          20 LOAD_CONST               5 ('eater')
             22 RETURN_VALUE
None
'''

生成器在UserList当中的应用

class company:
       def getitem(self, item):
                pass

list源码用c语言写的,看不到它的实现,
可以通过from collections import UserList查看python实现
from collections import UserList
from _collections_abc import MutableSequence,Sequence

Sequence源码:

class Sequence(Reversible, Collection):

    """All the operations on a read-only sequence.

    Concrete subclasses must override __new__ or __init__,
    __getitem__, and __len__.
    """

    __slots__ = ()

    @abstractmethod
    def __getitem__(self, index):
        raise IndexError

    def __iter__(self):
        i = 0
        try:
            while True:
                v = self[i]
                yield v
                i += 1
        except IndexError:
            return

    def __contains__(self, value):
        for v in self:
            if v is value or v == value:
                return True
        return False

    def __reversed__(self):
        for i in reversed(range(len(self))):
            yield self[i]

    def index(self, value, start=0, stop=None):
        '''S.index(value, [start, [stop]]) -> integer -- return first index of value.
           Raises ValueError if the value is not present.
        '''
        if start is not None and start < 0:
            start = max(len(self) + start, 0)
        if stop is not None and stop < 0:
            stop += len(self)

        i = start
        while stop is None or i < stop:
            try:
                v = self[i]
                if v is value or v == value:
                    return i
            except IndexError:
                break
            i += 1
        raise ValueError

    def count(self, value):
        'S.count(value) -> integer -- return number of occurrences of value'
        return sum(1 for v in self if v is value or v == value)

Sequence.register(tuple)
Sequence.register(str)
Sequence.register(range)
Sequence.register(memoryview)


使用生成器读取大文件的一个应用

1.准备input.txt
只有1行数据
{|}作为分隔符
文件不大作为测试用。

    bfksabcdkbaklbndklsnbklankldnklsnfklsnfsnflns{|}春花秋月{|}The Raspberry Pi Foundation是英国一个小型的慈善组织,成立的宗旨在于推广科技,而非以销售技术来营利。该基金会{|}过去从来没真的发表过一款产品,因而选择了两家全球渠道商e络盟和RS Components为其处理首批Raspberry Pi订单。面对{|}的是业余爱好者和热心DIY 的科技迷,Raspberry Pi销售非常不错。{|}Raspberry Pi是一款针对电脑业余爱好者、教师、小学生以及小型企业等用户的迷你电脑,预装Linux系统,体积仅信用{|}卡大小,搭载ARM架构处理器,运算性能和智能手机相仿{|}在接口方面,Raspberry Pi提供了可供键鼠使用的USB接口,此外还有快速以太网接口、SD卡扩展接口以及1个HDMI高{|}清视频输出接口,可与显示器或者TV相连{|}在查raspberry pi B版针脚定义的时候发现了r-pi短短的一{|}年时间已经经历了4代了,下面就把我搜集的几个版本图片分享给大家,简单说说各个版本的差别{|}最早诞生时,测试版的raspberry pi诞生于英国 伦敦国王大学 King’s College London {|}简称KCL 该学校有完善的电子开发环境,包括自己印制电路板,所以在最初版的raspberry {|}pi在树莓派Logo左侧有该电路板的编号 KCL-8-94V-0 ,板子所用零件都是杂七杂八非生产{|}物料提供,最初版的实物照片只在官方论坛的一些内部用户帖子中出现,市面没有流通{|}正式面世量产的第一版和它非常相向,基本零件规格使用上没有差别,只是插接件{|}贴片元件均使用工厂批量生产的规格,用料好,板子脱去了beta版的青涩,变得成熟性感。{|}正式第一版上市后各大媒体开始疯狂报道,树莓派的队伍也越来越壮大{|}球Geek的摆弄,很早就有了超频的内核出现,直到2012-8-16开始,官方也提供了超频内核,并开放{|}了config.txt用于自定义超频,不过,这是在发布第二版之后才官方开放的。

2.读取的代码:



#读取大文件500G  文件只有一行
# f=open()
# f.readline()和f.readlines()这两个
# 都是直接将所有内容一次性直接放到内存当中的

'''
f.read()很多人认为它是一次性将文件读入到我们的内存当中,实际上
这里面如果我们传递一个参数数字200它就只会读出200个字符,如果我
们接着继续f.read(300),它就会接着我们上一次的偏移量进行读取,这个
偏移量对象内部已经维护好了,我们不需要维护它之前读过的偏移量。
我们只需要反复的多次调用f.read()就可以完成继续读取数据。
'''
 #             文件对象 分隔符
def myreadlines(f,newline):
    #声明一个缓存 存储已经读出来的数据
    buf=""
    while True:

        '''
        这个while循环使用来处理f.read(4096*10)有可能读取数行数据
        则会包含多个分隔符,这个while循环不断进行判断是否只有一个
        分隔符
        '''
        #查询 缓存中是否包含了分隔符
        while newline in buf:
            #找出分隔符在缓存字符串的位置
            pos=buf.index(newline)
            #使用生成器将已缓存的数据返回
            yield buf[:pos]
            #取出分隔符后面的数据
            buf=buf[pos+len(newline):]
        chunk=f.read(4096*10)
        #说明已经读到了文件的结尾
        if not chunk:
            yield buf
            break
        buf+=chunk


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


"""
打印结果:
H:\ANACONDA\python.exe I:/ainlp/pythonHight/chapter09/readFile.py
bfksabcdkbaklbndklsnbklankldnklsnfklsnfsnflns
春花秋月
The Raspberry Pi Foundation是英国一个小型的慈善组织,成立的宗旨在于推广科技,而非以销售技术来营利。该基金会
过去从来没真的发表过一款产品,因而选择了两家全球渠道商e络盟和RS Components为其处理首批Raspberry Pi订单。面对
的是业余爱好者和热心DIY 的科技迷,Raspberry Pi销售非常不错。
Raspberry Pi是一款针对电脑业余爱好者、教师、小学生以及小型企业等用户的迷你电脑,预装Linux系统,体积仅信用
卡大小,搭载ARM架构处理器,运算性能和智能手机相仿
在接口方面,Raspberry Pi提供了可供键鼠使用的USB接口,此外还有快速以太网接口、SD卡扩展接口以及1个HDMI高
清视频输出接口,可与显示器或者TV相连
在查raspberry pi B版针脚定义的时候发现了r-pi短短的一
年时间已经经历了4代了,下面就把我搜集的几个版本图片分享给大家,简单说说各个版本的差别
最早诞生时,测试版的raspberry pi诞生于英国 伦敦国王大学 King’s College London 
简称KCL 该学校有完善的电子开发环境,包括自己印制电路板,所以在最初版的raspberry 
pi在树莓派Logo左侧有该电路板的编号 KCL-8-94V-0 ,板子所用零件都是杂七杂八非生产
物料提供,最初版的实物照片只在官方论坛的一些内部用户帖子中出现,市面没有流通
正式面世量产的第一版和它非常相向,基本零件规格使用上没有差别,只是插接件
贴片元件均使用工厂批量生产的规格,用料好,板子脱去了beta版的青涩,变得成熟性感。
正式第一版上市后各大媒体开始疯狂报道,树莓派的队伍也越来越壮大
球Geek的摆弄,很早就有了超频的内核出现,直到2012-8-16开始,官方也提供了超频内核,并开放
了config.txt用于自定义超频,不过,这是在发布第二版之后才官方开放的。
"""



完结

下一篇 python socket 编程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值