平台网站建设外包,wordpress4.0.x,青少年编程培训教育,哈尔滨网站建设 seo当我们需要处理一个大量的数据集合时#xff0c;一次性将其全部读入内存并处理可能会导致内存溢出。此时#xff0c;我们可以采用迭代器Iterator和生成器Generator的方法#xff0c;逐个地处理数据#xff0c;从而避免内存溢出的问题。
迭代器是一个可以逐个访问元素的对象…当我们需要处理一个大量的数据集合时一次性将其全部读入内存并处理可能会导致内存溢出。此时我们可以采用迭代器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_iteratoritem.__next__()
1next(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 x2)的数据. 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,hList [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_listos.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))
0print(next(generator))
1print(next(generator))
4print(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 sysyie( i**2 for i in range(1,10) )next(yie)
1next(yie)
4next(yie)
9 for j in ( i**2 for i in range(1,10)):print(j/2)3.3 队列的使用
队列是一个多线程编程中常用的数据结构,它提供了一种可靠的方式来安全地传递数据和控制线程间的访问. 在多线程环境下,如果没有同步机制,多个线程同时访问共享资源,可能会导致数据混乱或者程序崩溃.而Queue队列就是一种线程安全的数据结构,它提供了多个线程访问和操作的接口,可以保证多个线程之间的数据安全性和顺序性. 通过Queue队列,一个线程可以将数据放入队列,而另一个线程则可以从队列中取出数据进行处理,实现了线程之间的通信和协调.
先进先出队列: 先来介绍简单的队列例子,以及队列的常用方法的使用,此队列是先进先出模式.
import queueq queue.Queue(5) #默认maxsize0无限接收,最大支持的个数
print(q.empty()) #查看队列是否为空,如果为空则返回Trueq.put(1) #PUT方法是,向队列中添加数据
q.put(2) #第二个PUT,第二次向队列中添加数据
q.put(3,blockFalse,timeout2) #是否阻塞:默认是阻塞blockTrue,timeout超时时间print(q.full()) #查看队列是否已经放满
print(q.qsize()) #队列中有多少个元素
print(q.maxsize) #队列最大支持的个数print(q.get(blockFalse,timeout2)) #GET取数据
print(q.get())
q.task_done() #join配合task_done,队列中有任务就会阻塞进程,当队列中的任务执行完毕之后,不在阻塞
print(q.get())
q.task_done()
q.join() #队列中还有元素的话,程序就不会结束程序,只有元素被取完配合task_done执行,程序才会结束import queuedef 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 queueq queue.LifoQueue()q.put(wang)q.put(rui)q.put(ni)q.put(hao)print(q.get())
haoprint(q.get())
niprint(q.get())
ruiprint(q.get())
wangprint(q.get())优先级队列: 此类队列,可以指定优先级顺序,默认从高到低排列,以此根据优先级弹出数据. import queueq 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 queueq queue.deque()q.append(1)q.append(2)q.append(3)q.append(4)q.append(5)q.appendleft(6)print(q.pop())
5print(q.pop())
4print(q.popleft())
6print(q.popleft())
1print(q.popleft())
2生产者消费者模型: 生产者消费者模型,是各种开发场景中最常用的开发模式,以下是模拟的模型.
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(targetproductor,args(i,))t.start()for j in range(5): #负责取票,两个用户取票t threading.Thread(targetconsumer,args(j,))t1 threading.Thread(targetconsumer,args(j,))t.start()t1.start()本文作者 王瑞 本文链接 https://www.lyshark.com/post/1c1ebaa1.html 版权声明 本博客所有文章除特别声明外均采用 BY-NC-SA 许可协议。转载请注明出处