python全栈学习总结五:迭代器和生成器

一 迭代器

1 什么是迭代器协议

  迭代器协议:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么引起一个Stoplteration异常,以终止迭代(只能往后走不能往前退)

  可迭代对象:实现了迭代器协议的对象(如何实现:对象内部定义一个__iter__()方法)

  协议是一种约定,可迭代对象实现了迭代器协议,python的内部工具(如for循环,sum,min,max函数等)使用迭代器协议访问对象。

2 自定义迭代器

class MyIterator:
    #自定义迭代器类
    def __init__(self,x = 2,xmax = 63):
        self.__mul,self.__x = x,x
        self.__xmax = xmax

    def __iter__(self): #定义迭代器协议方法,返回类本身
        return  self

    def __next__(self):#定义迭代器协议方法
        if self.__x and self.__x !=1:
            self.__mul *= self.__x
            if self.__mul <= self.__xmax:
                return  self.__mul
            else :
                raise StopIteration
        else :
            raise StopIteration

if __name__ == ‘__main__‘:
    myiter = MyIterator(3,150) #实例化迭代器MyIterator
    for i in myiter:
        print("迭代的数据元素为:",i)

3 可迭代对象

  字符串,列表,元组,字典,集合,文件(str,list,tuple,dict,set,file)均为可迭代对象,通过for循环调用对象内部的__iter__方法,变成可迭代对象

  使用的迭代器协议函数

  x = ‘hell‘

  iter_x = x.__iter__()  #转化为可迭代对象,遵循迭代协议

  iter_x.__next__()  #转换后,可以使用__next__()方法来进行迭代

  next(iter_x)#也可以使用next函数进行迭代

  for循环的实质是在调用next方法或函数

  另外两个迭代函数
  iter(iterable)  参数iterable为可迭代类型

  iter(callable,sentine) 参数callable是可调用类型,一般为函数,第二个参数为哨兵,当第一个参数(函数)调用返回值等于第二个参数的值时,迭代或遍历停止。

class Counter: #定义用于计数的类
    def __init__(self,x=0): #定义构造函数,初始化实例属性
        self.x = x
counter = Counter()  #初始化实例类Counter
def used_iter():#定义用于iter()函数的函数
    counter.x +=2 #修改计数类中的实例属性的值
    return counter.x

for i in iter(used_iter,8):  #迭代iter()函数产生的迭代器
    print("本次遍历的数值:",i)

4 for和while操作可迭代对象,输出相同

x = ‘hello‘
for i in x:
    print(i)

x = ‘hello‘
x_iter = x.__iter__()
while True:
    try:
        print(x_iter.__next__())
    except StopIteration:
        print("迭代循环完成!")
        break

二 生成器

  生成器:一种数据类型,自动实现了迭代器协议(其他的数据类型需要调用自己内置的__iter__方法),所以生成器就是可迭代对象

1 三元表达式与列表解析

  三元表达式:res = ‘good‘ if num == True else ‘bad‘    #当num为True时,res的结果为‘good’,否则res的结果为‘bad‘

  列表解析:l = [i for i in range(10)]  #生成列表l = [0,1,2,3,4,5,6,7,8,9]

        l1 = [i for i in range(10) if i>5]   #三元表达式与列表解析相结合。

2 生成器表达式创建

  (1)生成器表达式:num = (i for i in range(10) if i > 5)  #注意列表解析是用的[]而生成器表达式是()

#列表解析
ret_list = []
for i in range(10):
    ret_list.append(" 包子%s"%i)
print(ret_list)
ret_list = ["包子%s"%i for i in range(10)]
print(ret_list)
ret_list = ("包子%s"%i for i in range(10))
print(ret_list)
print(ret_list.__next__())
print(ret_list.__next__())
print(ret_list.__next__())

注意观察列表解析和生成器创建的区别:列表解析一次生成列表,而生成器只是创建一个生成器对象,需要调用next方法才能访问。列表解析数据很多时,需要占用大量的内存。生成器的好处显而易见,用的时候才生成。

#生成器创建+三元判断
ret_list = ("包子%s"%i for i in range(10) if i > 5)
print(ret_list)
print(ret_list.__next__())
print(ret_list.__next__())
print(ret_list.__next__())

(2)生成器对象是通过yield关键字定义的函数对象,因此,生成器也是一个函数,生成器用于生成一个值的序列,以便在迭代中使用。

def myYiled(n): #定义一个生成器(函数)
    while n>0:
        print("开始生成...:")
        yield  n #yield语句,用于返回给调用者其后表达式的值
        print("完成一次...")
        n -= 1
if __name__ == ‘__main__‘:
    for i in myYiled(4):
        print("遍历得到的值:",i)

    print(‘*‘*10)
    my_yield = myYiled(3)
    print(‘已经实例化生成器对象!‘)
    print(my_yield.__next__())
    print(‘第二次调用__next__()方法‘)
    print(my_yield.__next__())
    print("第三次开始调用!")
    print(next(my_yield))

运行现象:

yield语句是生成器中的关键语句,生成器在实例化时并不会立即执行,而是等待调用其__next__()方法的时候才开始执行,并且当程序运行完yield语句后就会保持(hold)住,即保持当前状态且停止运行,等待下一次遍历时,才恢复运行!如上图!!!!

使用生成器,可以生成一个值的序列用于迭代,并且这个值的序列不是一次生成的,而是使用一个,再生成一个,的确可以使程序节约大量内存!

yield语句不仅可以使函数成为生成器和返回值,还可以接收调用者传来的数值。但值得注意的是:第一次调用生成器不能传给生成器None以外的值,否则会引发错误!使用生成的send方法传值!

def myYield(n):
    while n >  0:
        rcv = yield  n #rcv用来接收调用者传来的值
        n -= 1
        if rcv is not None:
            n = rcv
if __name__ == ‘__main__‘:

    my_yield = myYield(3)
    print(my_yield.__next__())
    print(next(my_yield))

    print(‘--‘*20)
    print("传给生成器一个值,重新初始化生成器!")
    print(my_yield.send(5))
    for i in my_yield:
        print(i)

    my_yield = myYield(3)
    #print(my_yield.send(4))  #xxxx第一次调用就传值错误!!!
    print(my_yield.send(None)) #但是可以传None
    print(next(my_yield))
    print(my_yield.send(6))

3 生成器特性:只能取一次

利用生成器来计算总人口,从文件中读取数据,分析出人口的总数量,并计算出所占比例

def get_population():
    with open("人口统计",‘r‘,encoding=‘utf-8‘) as f:
        for p in f:
            yield p
num_p = get_population()
# print(num_p.__next__())
# print(next(num_p))
all_p = sum(int(eval(p)[‘population‘]) for p in num_p)  #eval提取数据类型字典
print("总人口:%s"%all_p)
num_p = get_population()#上面已经取完,重新调用生成器
for num in num_p:
    num_dict = eval(num)
    # print("%s的比例:%s%%"%(10,8))
    print("%s的比例:%.2f%%"%(num_dict[‘name‘],int(num_dict[‘population‘])*100/all_p))
#人口统计文件{"name":"济南","population":"100"}
{"name":"青岛","population":"200"}
{"name":"烟台","population":"300"}
{"name":"潍坊","population":"400"}
{"name":"菏泽","population":"500"}
{"name":"临沂","population":"600"}

上面例程中,调用内置函数sum求和,使用生成器的方式计算,没有使用列表解析的方式,节省了大量内存,同理使用max,min等类似!一定要用生成器的方法!一个一个的计算!

4 生成器与协程(生产者与消费者)

运用send()方法来重置生成器的生成序列,也成为协程,是一种解决程序并发的方法!

def consumer(): #定义一个消费者模型(生成器协程)
    print("等待接收处理任务...")
    while True:
        data = (yield ) #模拟接收并处理任务
        print(‘收到任务!‘) #此处可以执行函数调用来完成相关任务

def producer():
    c = consumer()
    c.__next__()
    for i in range(5):
        print("发送一个任务...‘,‘任务%d"%i)
        c.send(‘任务%d‘%i)

if __name__ == ‘__main__‘:
    producer()

原文地址:https://www.cnblogs.com/qilvzhuiche/p/9374838.html

时间: 2024-11-08 05:00:28

python全栈学习总结五:迭代器和生成器的相关文章

python全栈学习路线

查询目录 一,硬件                                                                    十一,数据库 二,Linux基础                                                           十二,前端 三,python基础                                                        十三,Django 四,python文件处理   

python全栈学习--day4

列表 说明:列表是python中的基础数据类型之一,它是以[]括起来,每个元素以逗号隔开,而且他里面可以存放各种数据类型比如: 1 li = ['alex',123,Ture,(1,2,3,'wusir'),[1,2,3,'小明',],{'name':'alex'}] 列表相比于字符串,不仅可以储存不同的数据类型,而且可以储存大量数据.列表是有序的,有索引值,可切片,方便取值. 索引,切片,步长 li = ['xiao',123,True,(1,2,3,'wusir'),[1,2,3,'小明',

python 全栈开发,Day13(迭代器,生成器)

一.迭代器 python 一切皆对象 能被for循环的对象就是可迭代对象 可迭代对象: str,list,tuple,dict,set,range 迭代器: f1文件句柄 dir打印该对象的所有操作方法 s = 'python' print(dir(s)) 执行输出: ['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__

Python全栈学习:如何安装Python方法,详解!

因为Python是跨平台的,它可以运行在Windows.Mac和各种Linux/Unix系统上.在Windows上写Python程序,放到Linux上也是能够运行的. 要开始学习Python编程,首先就得把Python安装到你的电脑里.安装后,你会得到Python解释器(就是负责运行Python程序的),一个命令行交互环境,还有一个简单的集成开发环境. 安装Python 3.7 目前,Python有两个版本,一个是2.x版,一个是3.x版,这两个版本是不兼容的.由于3.x版越来越普及,我们的教程

python全栈学习--面向对象进阶3

复习: #反射 必须会,必须能看的懂,必须知道在哪儿用 #hasattr  getattr setattr delattr 内置方法 必须能看懂 能用尽量用 __len__len(obj)的结果依赖于obj.__len()__的结果,计算对象的长度 __hash__ hash(obj)的结果依赖于obj.__hash__()的结果,结算对象的hash值 __eq__ obj1 == obj2 的结果依赖于obj.__eq__()的结果,用来判断相等 __str__ str(obj) print(

python全栈学习--day31(正则)

try: '''可能会出现异常的代码''' except ValueError: ''''打印一些提示或者处理的内容''' except NameError: '''...''' except Exception: '''万能异常不能乱用''' try: '''可能会出现异常的代码''' except ValueError: ''''打印一些提示或者处理的内容''' except NameError: '''...''' except Exception: '''万能异常不能乱用''' else

python全栈学习总结更新字符串:字符串格式化方法

一百分号方式 """ 百分号方式 %[(name)][flags][width].[precision]typecode (name) 可选,用于选择指定的key flags 可选,可供选择的值有: + 右对齐:正数前加正好,负数前加负号: - 左对齐:正数前无符号,负数前加负号: 空格 右对齐:正数前加空格,负数前加负号: 0 右对齐:正数前无符号,负数前加负号:用0填充空白处 width 可选,占有宽度 .precision 可选,小数点后保留的位数 typecode 必

python全栈学习总结二:数字、字符串、列表、元组、字典重要特点及方法

一 python中数据类型 整形:int 字符串:str 列表:list 元组:tuple 字典:dict 布尔值:bool 浮点型:float 一切皆对象,在python中,所有的数据类都是看做对象,故所有的类型名称都是类,通过类来建立对象,每个类中都有相应的方法,下面我们通过总结上面其中数据类型的特点以及常用的方法,来加深我们这些数据"类"的认识和理解. 二 各种数据类型总结 1 整形int 定义:age = 10 转换:value = int('158')  把字符串'158'转

Day-1 Python全栈学习

乘法表: i = 1while i <= 9: print(i,end=": ") j = 1 while j <= i: print("%d*%d=%d" %(i,j,i*j),end=" ") j += 1 i += 1 print() 运行结果