3.0 Python 迭代器与生成器

这篇具有很好参考价值的文章主要介绍了3.0 Python 迭代器与生成器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

当我们需要处理一个大量的数据集合时,一次性将其全部读入内存并处理可能会导致内存溢出。此时,我们可以采用迭代器Iterator和生成器Generator的方法,逐个地处理数据,从而避免内存溢出的问题。

迭代器是一个可以逐个访问元素的对象,它实现了python的迭代协议,即实现了__iter__()__next__()方法。通过调用__next__()方法,我们可以逐个访问迭代器中的元素,直到所有元素都被访问完毕,此时再次调用__next__()方法会引发StopIteration异常。

生成器是一种特殊的迭代器,它的实现方式更为简洁,即通过yield语句来实现。生成器函数使用yield语句返回值,当生成器函数被调用时,它会返回一个生成器对象,通过调用__next__()方法来逐个访问生成器中的元素,直到所有元素都被访问完毕,此时再次调用__next__()方法会引发StopIteration异常。

使用迭代器和生成器可以有效地避免内存溢出问题,并且代码实现也更为简洁、高效。在python中,很多内置函数和语言特性都支持迭代器和生成器的使用,例如for循环、列表推导式、生成器表达式等。

3.1 使用迭代器

迭代器可以通过内置函数iter()进行创建,同时可以使用next()函数获取下一个元素,如果迭代器没有更多的元素,则抛出StopIteration异常在for循环中,迭代器可以自动实现例如for x in my_iterable:语句就可以遍历my_iterable对象的所有元素。此外python中还有一种特殊的迭代器,称为生成器(generator),生成器是一种用简单的方法实现迭代器的方式,使用了yield语句,生成器在执行过程中可以暂停并继续执行,而函数则是一旦开始执行就会一直执行到返回。

创建基本迭代器: 首先声明列表,然后使用__iter__将其转为迭代器,并通过__next__遍历迭代对象.

>>> list = [1,2,3,4,5,6,7,8,9,10]
>>>
>>> item = list.__iter__()
>>> type(item)
<class 'list_iterator'>
>>>
>>> item.__next__()
1
>>> next(item)
2

迭代器遍历日志文件: 使用迭代器可以实现对文本文件或日志的遍历,该方式可以遍历大型文件而不会出现卡死现象.

# 手动访问迭代器中的元素,可以使用next()函数
>>> with open("passwd.log") as fp:
...     try:
...             while True:
...                     print(next(fp))
...     except StopIteration:
...             print("none")

# 通过指定返回结束值来判断迭代结束
>>> with open("passwd.log") as fp:
...     while True:
...             line = next(fp,None)
...             if line is None:
...                     break
...             print(line)

循环遍历迭代元素: 由于迭代器遍历结束会报错,所以要使用try语句抛出一个StopIteration结束异常.

>>> listvar = ["吕洞宾", "张果老", "蓝采和", "特乖离", "和香菇", "汉钟离", "王文"]
>>> item = listvar.__iter__()
>>>
>>> while True:
...     try:
...             temp = next(item)
...             print(temp)
...     except StopIteration:
...             break

迭代器与数组之间互转: 通过使用enumerate方法,并将列表转为迭代器对象,然后将对象转为制定格式.

>>> listvar = ["吕洞宾", "张果老", "蓝采和", "特乖离", "和香菇", "汉钟离", "王文"]
>>>
>>> iter = enumerate(listvar)  # 转换为迭代器
>>> dict = tuple(iter)         # 转换为元组
>>> dict
((0, '吕洞宾'), (1, '张果老'), (2, '蓝采和'), (3, '特乖离'), (4, '和香菇'), (5, '汉钟离'), (6, '王文'))
>>>
>>> dict = list(iter)
>>> dict
[(0, '吕洞宾'), (1, '张果老'), (2, '蓝采和'), (3, '特乖离'), (4, '和香菇'), (5, '汉钟离'), (6, '王文')]

3.2 使用生成器

生成器是一种可以动态生成数据的迭代器,不同于列表等容器类型一次性把所有数据生成并存储在内存中,生成器可以在需要时动态生成数据,这样可以节省内存空间和提高程序效率.使用生成器可以通过for循环遍历序列、列表等容器类型,而不需要提前知道其中所有元素.生成器可以使用yield关键字返回值,每次调用yield会暂停生成器并记录当前状态,下一次调用时可以从上一次暂停的地方继续执行,而生成器的状态则保留在生成器对象内部.除了使用next()函数调用生成器外,还可以使用send()函数向生成器中发送数据,并在生成器内部使用yield表达式接收发送的数据.

当我们调用一个生成器函数时,其实返回的是一个迭代器对象
只要表达式中使用了yield函数,通常将此类函数称为生成器(generator)
运行生成器时,每次遇到yield函数,则会自动保存并暂停执行,直到使用next()方法时,才会继续迭代
跟普通函数不同,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器

在学习生成器之前,需要一些前置知识,先来研究一下列表解析,列表解析是python迭代机制的一种应用,它常用于实现创建新的列表,因此要放置于[]中,列表解析非常灵活,可以用户快速创建一组相应规则的列表元素,且支持迭代操作.

列表生成式基本语法: 通过列表生成式,我们可以完成数据的生成与过滤等操作.

>>> ret = [item for item in range(30) if item >0]
>>> print(ret)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
>>>
>>> ret = [item for item in range(30) if item >3]
>>> print(ret)
[4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
>>>
>>> ret = [item for item in range(30) if item%2!=0]
>>> ret
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29]

列表式求阶乘: 通过列表解析式,来实现列表的迭代求阶乘,并且只打印大于2(if x>=2)的数据.

>>> var = [1,2,3,4,5]
>>> retn = [ item ** 2 for item in var ]
>>> retn
[1, 4, 9, 16, 25]
>>>
>>> retn = [ item ** 2 for item in var if item >= 2 ]
>>> retn
[4, 9, 16, 25]
>>>
>>> retn = [ (item**2)/2 for item in range(1,10) ]
>>> retn
[0.5, 2.0, 4.5, 8.0, 12.5, 18.0, 24.5, 32.0, 40.5]

数据转换: 通过使用列表生成式,实现将一个字符串转换成一个合格的列表.

>>> String = "a,b,c,d,e,f,g,h"
>>> List = [item for item in String.split(",")]
>>> List
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']

数据合并: 通过列表解析式,实现迭代将两个列表按照规律合并.

>>> temp1=["x","y","z"]
>>> temp2=[1,2,3]
>>> temp3=[ (i,j) for i in temp1 for j in temp2 ]
>>> temp3
[('x', 1), ('x', 2), ('x', 3), ('y', 1), ('y', 2), ('y', 3), ('z', 1), ('z', 2), ('z', 3)]

文件过滤: 通过使用列表解析,实现文本的过滤操作.

>>> import os

>>> file_list=os.listdir("/var/log")
>>> file_log=[ i for i in file_list if i.endswith(".log") ]
>>> print(file_log)
['boot.log', 'yum.log', 'ecs_network_optimization.log', 'ntp.log']

>>> file_log=[ i for i in os.listdir("/var/log") if i.endswith(".log") ]
>>> print(file_log)
['boot.log', 'yum.log', 'ecs_network_optimization.log', 'ntp.log']

接下来我们就来研究一下生成器吧,生成器类似于返回值为数组的一个函数,这个函数可以接受参数,可以被调用,但不同于一般的函数会一次性返回包括了所有数值的数组,生成器一次只能产生一个值,这样消耗的内存数量将大大减小,而且允许调用函数可以很快的处理前几个返回值,因此生成器看起来像是一个函数,但是表现得却像是迭代器.

我们先来看以下两种情况的对比,第一种方法很简单,只有把一个列表生成式的[]中括号改为()小括号,就创建了一个生成器.

>>> lis = [x*x for x in range(10)]
>>> print(lis)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

>>> generator = (x*x for x in range(10))
>>> print(generator)
<generator object <genexpr> at 0x0000022E5C788A98>

如上例子,第一个lis通过列表生成式,创建了一个列表,而第二个generator则打印出一个内存地址,如果我们想获取到第二个变量中的数据,则需要迭代操作,如下所示:

>>> generator = (x*x for x in range(10))

>>> print(next(generator))
0
>>> print(next(generator))
1
>>> print(next(generator))
4
>>> print(next(generator))
9

以上可以看到,generator保存的是算法,每次调用next(generaotr),就计算出他的下一个元素的值,直到计算出最后一个元素,使用for循环可以简便的遍历出迭代器中的数据,因为generator也是可迭代对象.

>>> generator = (x*x for x in range(10))
>>> 
>>> for i in generator:
    print(i,end="")

0149162536496481

生成器表达式并不真正创建数字列表,而是返回一个生成器对象,此对象在每次计算出一个条目后,把这个条目"产生"(yield)出来,生成器表达式使用了"惰性计算"或称作"延迟求值"的机制序列过长,并且每次只需要获取一个元素时,应当考虑使用生成器表达式而不是列表解析.

>>> import sys
>>> 
>>> yie=( i**2 for i in range(1,10) )
>>> next(yie)
1
>>> next(yie)
4
>>> next(yie)
9

>>> for j in ( i**2 for i in range(1,10)):print(j/2)

3.3 队列的使用

队列是一个多线程编程中常用的数据结构,它提供了一种可靠的方式来安全地传递数据和控制线程间的访问. 在多线程环境下,如果没有同步机制,多个线程同时访问共享资源,可能会导致数据混乱或者程序崩溃.而Queue队列就是一种线程安全的数据结构,它提供了多个线程访问和操作的接口,可以保证多个线程之间的数据安全性和顺序性. 通过Queue队列,一个线程可以将数据放入队列,而另一个线程则可以从队列中取出数据进行处理,实现了线程之间的通信和协调.

先进先出队列: 先来介绍简单的队列例子,以及队列的常用方法的使用,此队列是先进先出模式.

import queue

q = queue.Queue(5)                    #默认maxsize=0无限接收,最大支持的个数
print(q.empty())                      #查看队列是否为空,如果为空则返回True

q.put(1)                              #PUT方法是,向队列中添加数据
q.put(2)                              #第二个PUT,第二次向队列中添加数据
q.put(3,block=False,timeout=2)        #是否阻塞:默认是阻塞block=True,timeout=超时时间

print(q.full())                       #查看队列是否已经放满
print(q.qsize())                      #队列中有多少个元素
print(q.maxsize)                      #队列最大支持的个数

print(q.get(block=False,timeout=2))   #GET取数据
print(q.get())                        
q.task_done()       #join配合task_done,队列中有任务就会阻塞进程,当队列中的任务执行完毕之后,不在阻塞
print(q.get())
q.task_done()
q.join()            #队列中还有元素的话,程序就不会结束程序,只有元素被取完配合task_done执行,程序才会结束
import queue

def show(q,i):
    if q.empty() or q.qsize() >= 1:
        q.put(i)   #存队列
    elif q.full():
        print('queue not size')

que = queue.Queue(5)   #允许5个队列的队列对象
for i in range(5):
    show(que,i)
print('queue is number:',que.qsize())  #队列元素个数
for j in range(5):
    print(que.get())  #取队列
print('......end')

后进先出队列: 这个队列则是,后进先出,也就是最后放入的数据最先弹出,类似于堆栈.

>>> import queue
>>>
>>> q = queue.LifoQueue()
>>>
>>> q.put("wang")
>>> q.put("rui")
>>> q.put("ni")
>>> q.put("hao")
>>>
>>> print(q.get())
hao
>>> print(q.get())
ni
>>> print(q.get())
rui
>>> print(q.get())
wang
>>> print(q.get())

优先级队列: 此类队列,可以指定优先级顺序,默认从高到低排列,以此根据优先级弹出数据.

>>> import queue
>>>
>>> q = queue.PriorityQueue()
>>>
>>> q.put((1,"python1"))
>>> q.put((-1,"python2"))
>>> q.put((10,"python3"))
>>> q.put((4,"python4"))
>>> q.put((98,"python5"))
>>>
>>> print(q.get())
(-1, 'python2')
>>> print(q.get())
(1, 'python1')
>>> print(q.get())
(4, 'python4')
>>> print(q.get())
(10, 'python3')
>>> print(q.get())
(98, 'python5')

双向的队列: 双向队列,也就是说可以分别从两边弹出数据,没有任何限制.

>>> import queue
>>>
>>> q = queue.deque()
>>>
>>> q.append(1)
>>> q.append(2)
>>> q.append(3)
>>> q.append(4)
>>> q.append(5)
>>>
>>> q.appendleft(6)
>>>
>>> print(q.pop())
5
>>> print(q.pop())
4
>>> print(q.popleft())
6
>>> print(q.popleft())
1
>>> print(q.popleft())
2

生产者消费者模型: 生产者消费者模型,是各种开发场景中最常用的开发模式,以下是模拟的模型.文章来源地址https://www.toymoban.com/news/detail-642284.html

import queue,time
import threading
q = queue.Queue()

def productor(arg):
    while True:
        q.put(str(arg))
        print("%s 号窗口有票...."%str(arg))
        time.sleep(1)

def consumer(arg):
    while True:
        print("第 %s 人取 %s 号窗口票"%(str(arg),q.get()))
        time.sleep(1)

for i in range(10):                     #负责生产票数
    t = threading.Thread(target=productor,args=(i,))
    t.start()

for j in range(5):                      #负责取票,两个用户取票
    t = threading.Thread(target=consumer,args=(j,))
    t1 = threading.Thread(target=consumer,args=(j,))
    t.start()
    t1.start()

到了这里,关于3.0 Python 迭代器与生成器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python小姿势 - ## Python中的迭代器与生成器

    Python中的迭代器与生成器 在Python中,迭代是一个非常重要的概念,迭代器和生成器是迭代的两种最常见的形式。那么,迭代器与生成器有何不同呢? 首先,我们先来了解一下迭代器。 迭代器是一种对象,它可以记住遍历的位置,并在每次访问时返回下一个元素。迭代器只能

    2024年02月04日
    浏览(58)
  • 【Python】Python系列教程-- Python3 迭代器与生成器(二十)

    往期回顾: Python系列教程–Python3介绍(一) Python系列教程–Python3 环境搭建(二) Python系列教程–Python3 VScode(三) Python系列教程–Python3 基础语法(四) Python系列教程–Python3 基本数据类型(五) Python系列教程-- Python3 数据类型转换(六) Python系列教程-- Python3 推导式(

    2024年02月08日
    浏览(67)
  • python之迭代器和生成器

    当谈到Python中的迭代时,迭代器和生成器是两个很常见的概念。在本教程中,我将帮助您理解Python中迭代器和生成器的工作原理及其实现方式。 迭代器 Python中的迭代器是一种特殊的对象,可以用于遍历可迭代对象中的所有元素。所有的迭代器都实现了 __iter__() 和 __next__() 方

    2023年04月18日
    浏览(57)
  • 8 python的迭代器和生成器

    概述         在上一节,我们介绍了Python的模块和包,包括:什么是模块、导入模块、自定义模块、__name__、什么是包、创建包、导入包等内容。在这一节中,我们将介绍Python的迭代器和生成器。在Python中,迭代器是一个非常重要的概念,它使得我们能够遍历一个序列而无

    2024年02月10日
    浏览(41)
  • python中函数,装饰器,迭代器,生成器

    1.函数可以作为参数进行传递 2.函数可以作为返回值进行返回 3.函数名称可以当成变量一样进行赋值操作 作用:在不改变原有函数调用的情况下,给函数增加新的功能          即可以在函数前面增加新的功能,但不改变原来的代码 可迭代的数据类型都会提供迭代器,即可以

    2024年02月07日
    浏览(45)
  • 【python高级用法】迭代器、生成器、装饰器、闭包

    可迭代对象:可以使用for循环来遍历的,可以使用isinstance()来测试。 迭代器:同时实现了__iter__()方法和__next__()方法,可以使用isinstance()方法来测试是否是迭代器对象 使用类实现迭代器 两个类实现一个迭代器 一个类实现迭代器 可迭代对象与迭代器的总结 一个具备了__iter_

    2024年02月03日
    浏览(41)
  • Python教程(26)——Python迭代器和生成器详解

    Python中的迭代器是一种对象,它可以迭代(遍历)一个可迭代对象(比如列表、元组或字符串)的元素。迭代器用于实现迭代器协议,即包含 __iter__() 方法和 __next__() 方法。 迭代器的工作原理是每次调用 __next__() 方法时返回可迭代对象的下一个元素,当没有元素可迭代时,抛

    2024年02月19日
    浏览(45)
  • 【Python 4】列表与元组slice切片 迭代 列表生成式 生成器generator 迭代器Iterator对象

    在Python中,代码不是越多越好,而是越少越好 取一个list或tuple的部分元素是非常常见的操作 对这种经常取指定索引范围的操作,用循环十分繁琐,因此,Python提供了切片(Slice)操作符,能大大简化这种操作 L[0:3]表示,从索引0开始取,直到索引3为止,但不包括索引3 如果第

    2024年02月07日
    浏览(55)
  • python使用迭代生成器yield减少内存占用的方法

    在python编码中for循环处理任务时,会将所有的待遍历参量加载到内存中。 其实这本没有必要,因为这些参量很有可能是一次性使用的,甚至很多场景下这些参量是不需要同时存储在内存中的,这时候就会用到本文所介绍的迭代生成器yield。 首先我们用一个例子来演示一下迭代

    2024年04月28日
    浏览(31)
  • Python黑魔法:探秘生成器和迭代器的神奇力量

    在Python中,生成器和迭代器是实现惰性计算的两种重要工具,它们可以帮助我们更有效地处理数据,特别是在处理大数据集时,可以显著减少内存的使用。接下来,我们将详细介绍这两种工具。 迭代器是一种特殊的对象,它可以遍历一个集合中的所有元素。任何实现了__ite

    2024年02月12日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包