python迭代器创建序列_Python 基础7 迭代器 、生成器、序列、文件

本文详细介绍了Python中的迭代器、生成器、序列以及它们之间的关系。迭代器是访问可迭代对象的工具,通过next()函数获取数据。生成器分为生成器函数和生成器表达式,用于动态生成数据,节省内存。文章还讨论了容器、列表/集合/字典推导式,并提供了多个示例和练习题,帮助读者理解和掌握这些概念。
摘要由CSDN通过智能技术生成

在了解Python的数据结构时,容器(container)、可迭代对象(iterable)、迭代器(iterator)、生成器(generator)、列表/集合/字典推导式(list,set,dict comprehension)众多概念参杂在一起,难免让初学者一头雾水,我将用一篇文章试图将这些概念以及它们之间的关系捋清楚

容器(container)

容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取,可以用 in , not in 关键字判断元素是否包含在容器中。通常这类数据结构把所有的元素存储在内存中(也有一些特列并不是所有的元素都放在内存)在Python中,常见的容器对象有:

list, deque, ....

set, frozensets, ....

dict, defaultdict, OrderedDict, Counter, ....

tuple, namedtuple, …

str

容器比较容易理解,因为你就可以把它看作是一个盒子、一栋房子、一个柜子,里面可以塞任何东西。从技术角度来说,当它可以用来询问某个元素是否包含在其中时,那么这个对象就可以认为是一个容器,比如 list,set,tuples都是容器对象:

尽管绝大多数容器都提供了某种方式来获取其中的每一个元素,但这并不是容器本身提供的能力,而是 可迭代对象 赋予了容器这种能力,当然并不是所有的容器都是可迭代的。

迭代器 Iterator:

可迭代对象:list tuple dict set frozenset str range() reversed() map() sorted() filter();

迭代器是访问可迭代对象的工具(对象);

什么是可迭代对象? (拥有iter方法的对象 为 可迭代对象)。

1、什么是迭代器:

迭代器是指用iter(obj)函数返回的对象(实例)

迭代器可以用next(it) 函数获取可迭代对象的数据;

满足以上两个条件:1.有iter方法,有next方法。

2、迭代器相关函数:

iter(iterable) 从可迭代对象中返回一个迭代器,iterable必须是一个能提供一个迭代器的对象;

next(iterator) 从迭代器iterator中获取下一个记录,如果无法获取下一条记录,则触发stopIteration异常通知;

说明:迭代器只能往前取值,不能后退;

示例:

L= [2, 3, 4, 5, 7]

it= iter(L) #让可迭代对象L提供一个迭代器

next(it) #2

next(it) #3

next(it) #4

next(it) #5

next(it) #7

next(it) #StopIteration 异常通知

#此示意用while语句和迭代器来访问列表

L = [2, 3, 5, 7]

it=iter(L)whileTrue:try:

x=next(it)exceptStopIteration:break

#for 循环内部三件事

# 1.调用可迭代对象的iter方法 返回一个迭代器对象;

# 2.不断调用迭代器对象的next方法;

# 3.处理StopIteration异常;

生成器 Generator:

1、什么是生成器:

生成器是能够动态提供数据的对象,生成器对象也是可迭代对象;

生成器有两种:

1.生成器函数

2.生成器表达式  eg: s=(x*2 for x in range(10000000))

2、生成器函数定义:

含有yield语句的函数是生成器函数,此函数被调用将返回一个生成器对象;

注:yield翻译为(产生或生成)

yield语句

语法:

yield 表达式

说明:

1.yield 用于def 函数中,目的是将此函数作为生成器函数使用;

2.yield 用来生成数据,供迭代器的next(it) 函数使用;

3、生成器函数说明:

1.生成器函数的调用将返回一个生成器对象,生成器对象是可迭代对象;

2.生成器函数调用return 会触发一个StopIteration异常;

#yield.py#此示例示意函数yield 语句的生成器函数定义方式和用法

defmyyield():'''此函数因含有yield语句,所以是生成器函数'''

print('即将生成1')yield 1    #等同于return 1

print('即将生成3')yield 3

print('即将生成5')yield 5

print('即将生成7')yield 7

print('即将生成结束')

gen= myyield() #gen绑定的是生成器,生成器是可迭代对象

it = iter(gen) #返回迭代器

x= next(it) #next()语句调用时才开始执行生成器函数的语句(如print),直到遇见yield语句停止,我待下次next()语句调用;

print(x)print(x)print(next(it))print(next(it))print(next(it))print(next(it))

1 #斐波那契数列

2 #0 1 1 2 3 5 8 13 21

3 deffib(max):4 n,before,after = 0, 0, 1

5 while n <6>

7 yieldbefore8 before,after = after,before+after #注意此处赋值是先进行右边相加 再赋值

9 n += 1

10

11 g=fib(8)12 print(g)13 print(next(g))14 print(next(g))15 print(next(g))16 print(next(g))17 print(next(g))

还可通过yield实现在单线程的情况下实现伪并发运算的效果

1 #_*_coding:utf-8_*_

2 __author__ = 'Alex Li'

3

4 importtime5 defconsumer(name):6 print("%s 准备吃包子啦!" %name)7 whileTrue:8 baozi = yield

9

10 print("包子[%s]来了,被[%s]吃了!" %(baozi,name))11

12

13 defproducer(name):14 c = consumer('A')15 c2 = consumer('B')16 c.__next__()17 c2.__next__()18 print("alex开始准备做包子啦!")19 for i in range(10):20 time.sleep(1)21 print("做了2个包子!")22 c.send(i)23 c2.send(i)24

25 producer("alex")

4、生成器表达式:

语法:

(表达式 for 变量 in 可迭代对象 [if 真值表达式])

说明:

if 子句可以省略

作用:

用推导式的形式生成一个新的生成器;

示例:

gen= (x ** 2 for x in range(1, 5))

it=iter(gen)

next(it)#1

next(it) #4

next(it) #9

next(it) #16

>>> (x ** 2 for x in range(1, 5)) #注意 生成器数据是现用,现生成

at 0x00000222A1C796D8>

>>>示例:

L= [2, 3, 5, 7]

Lst= [x + 1 for x in L] #列表推导式 或 列表生成式

it =iter(Lst)print('1',next(it)) #3

L[1] = 30

print(L)print('2',next(it)) #4

L= [2, 3, 5, 7]

Lst= (x + 1 for x in L) #生成器表达式,不存储数据

it =iter(Lst)print('3',next(it)) #3

L[1] = 30

print(L)print('4',next(it)) #31

迭代工具函数:

作用:

生成一个个性化的可迭代对象

函数名:

zip(iter1, iter2, iter3, .....) 返回一个zip对象,此对象用于生成一个元组,此元组中的元素分别由iter1,iter2可迭代对象中的元组构成(元组个数由最小的可迭代对象决定);

enumerate(iterable, start=0) 生成带索引的枚举对象,返回的迭代类型为索引-值对(index-value)对,默认索引从零开始,也可用start指定; 序号;

#示例:

numbers = [10086, 10000, 10010, 95588]

names= ['中国移动','中国电信','中国联通']for t inzip(numbers, names):print(t)for n, a in zip(numbers, names): #注 for 变量列表 in zip(...) 序列赋值

print(a, '的客服号码是', n)for t in zip(range(1000), numbers, names):print(t)for t inenumerate(names):print(t)for t in enumerate(names, 1000):print(t)

#练习#写一个程序,读入任意行文字,当输入空行时,结束输入,打印带有行号的输入结果#如:#请输入:hello # 输出如下:# 第1行:hello

defread_lines():

L=[]whileTrue:

s= input('请输入:')if nots:breakL.append(s)returnLdefprint_lines(L):'''打印带有行号的文字信息'''

for t in enumerate(lines, 1):print('第%d行:%s' %t)if __name__ == '__main__':

lines=read_lines()

print_lines(lines)

文件读取

defread_file(fpath):

BLOCK_SIZE= 1024with open(fpath,'rb') as f:whileTrue:

block=f.read(BLOCK_SIZE)ifblock:yieldblockelse:return

如果直接对文件对象调用 read() 方法,会导致不可预测的内存占用。好的方法是利用固定长度的缓冲区来不断读取文件内容。通过 yield,我们不再需要编写读文件的迭代类,就可以轻松实现文件读取。

My:生成器对象就是一种特殊的迭代器对象,满足迭代器协议,可以调用next;对生成器对象for 循环时,调用iter方法返回了生成器对象,然后再不断next迭代,而iter和next都是在yield内部实现的。

练习1:使用文件读取,找出文件中最长的行的?

max(len(x.strip()) for x in open('/hello/abc','r'))

View Code

练习2:

defadd(s, x):return s +xdefgen():for i in range(4):yieldi

base=gen()for n in [1, 10]:

base= (add(i, n) for i inbase)printlist(base)

解析'''核心语句就是:

for n in [1, 10]:

base = (add(i, n) for i in base)

在执行list(base)的时候,开始检索,然后生成器开始运算了。关键是,这个循环次数是2,也就是说,有两次生成器表达

式的过程。必须牢牢把握住这一点。

生成器返回去开始运算,n = 10而不是1没问题吧,这个在上面提到的文章中已经提到了,就是add(i, n)绑定的是n这个

变量,而不是它当时的数值。

然后首先是第一次生成器表达式的执行过程:base = (10 + 0, 10 + 1, 10 + 2, 10 +3),这是第一次循环的结

果(形象表示,其实已经计算出来了(10,11,12,3)),然后第二次,

base = (10 + 10, 11 + 10, 12 + 10, 13 + 10) ,终于得到结果了[20, 21, 22, 23].'''

send的工作方式:

deff():print("ok")

s=yield 7

print(s)yield 8f=f()print(f.send(None))print(next(f))#print(f.send(None))等同于print(next(f)),执行流程:打印ok,yield7,当再next进来时:将None赋值给s,然后返回8,可以通过断点来观察

序列:list, str, tuple, bytes, bytearray

字节串 bytes :(也叫字节序列)

1、字节串bytes

作用:存储以字节为单位的数据

说明:

字节串是不可变的字节序列

字节是0~255的整数(0x00~0xFF; 0b00000000~0b11111111)

创建空字节的字面值:

b = b''b绑定空字节串

b = b""b绑定空字节串

b = b''''''b绑定空字节串

b = b""""""b绑定空字节串

创建非空字节串的字面值:

b = b'ABCD'

b = b'\x41\x42'

2、字节串的构造函数 bytes:

bytes()生成一个字的字节串,等同于b'';

bytes(整形可迭代对象)#用可迭代对象初始化一个字节串

bytes(整数n)生成n个值为0的字符串

bytes(字符串,encoding='utf-8')用字符串的转换编码生成一个字节串

示例:

b=bytes()

b= bytes(range(0, 255))

b= bytes(10)

b= bytes('你好', 'utf-8')>>> bytes('hello','GBK') #b'hello'

>>> bytes('hello','utf-8') #b'hello'

国家标准码:

GBK

GB2312

GB18030

Unicode标准码:

Unicode(utf-8)

3、字节串的运算:a 97 A 65 0 48

+ += * *=

< <= > >= == !=

in / not in

示例>>> b = b'ABC' + b'123'

>>> len(b) #6

>>> b #b'ABC123'

>>> max(b) #67

>>> min(b) #49

>>> sum(b) #348

>>> b'abC' > b'abD' #False

>>> b'A' in b #True

>>> 49 in b #True

>>> b[::2] #b'AC2'

4、字节串的索引和切片:

5、字节串的函数:

len(x) max(x) min(x) sum(x) any(x) all(x)

6、字节串bytes 与 字符串str 的区别:

bytes 存储字节(0~255)

str 存储unicode字符(0~65535或更大)

str与bytes转换:

编码(encode)

str---------->bytes

b= s.encode(encoding='utf-8')

解码(decode)

bytes------------->str

s= b.decode(encoding='utf-8')

help(str.encode)>>> s = 'hello,你好'

>>> b = s.encode('utf-8')>>> b #b'hello,\xe4\xbd\xa0\xe5\xa5\xbd'

>>> s2 = b.decode('utf-8')>>> s2 #'hello,你好'

list--->tuple

set--->frozenset

bytearray----> bytes

字节数组 bytearray:

可变的字节序列;

创建函数 bytearray:

bytearray()创建字节数组

bytearray(可迭代对象)同bytes(可迭代对象)

bytearray(整数n)

bytearray(字符串,encoding='utf-8')

>>> ba =bytearray()>>> type(ba) #

>>> ba #bytearray(b'')

>>> bytearray(range(65,70)) #bytearray(b'ABCDE')

>>> bytearray(10) #含有10字节都为0的字节数组,最大值和最小值都为0;

bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')

运算操作:  + += * *=

比较运算:< <= > >= == !=

in / not in

函数:  len(x) max(x) min(x) sum(x) any(x) all(x)

索引 index / 切片 slice:

字节数组支持索引和切片赋值,规则同列表的索引和切片赋值规则;

示例:>>> ba = bytearray(b'ABCDEF')>>>ba

bytearray(b'ABCDEF')>>> ba[::2] = [48, 49, 50]>>>ba

bytearray(b'0B1D2F')>>>字节数组的方法:

详见: help(bytearray)

文件 file: (RAM 随机存储器)

文件是用于数据存储的单位;

文件通常用来长期存储数据;

文件中的数据是以字节为单位进行顺序存储的;

1、文件的操作流程:

1. 打开文件

2. 读/写文件

3. 关闭文件

注:任何的操作系统,同一个应用程序同时打开文件的数量有最大数限制,所以在用完文件后需要关闭;

2、文件的打开函数open

open(file, mode='rt') 用于打开一个文件,返回此文件流对象,如果打开文件失败,则会触发OSError错误;

3、文件的关闭方法:

F.close()关闭文件,释放系统资源;

文件常用方法:

F.close() 关闭文件(关闭后文件不能再读写会发生ValueError错误)

F.readline() 读取一行数据(包括行尾换行符\n), 如果到达文件尾则返回空行

F.readlines(max_chars=-1) 返回每行字符串的列表,max_chars为最大字符(或字节)数,

F.writelines(lines) 每行字符串的列表

F.flush() 把写入文件对象的缓存内容写入到磁盘

F.read(size= -1) 从一个文件流中最多读取size个字符

F.write(text) 写一个字符串到文件流中,返回写入的字符数

二进制文件操作方法:

F.tell() 返回当前文件流的绝对位置

F.seek(offset, whence=0) 改变数据流的位置,返回新的绝对位置

F.readable() 判断这个文件是否可读,可读返回True,否则返回False

F.writable() 判断这个文件是否可写,可写返回True,否则返回False

F.seekable() 返回这个文件对象是否支持随机定位

F.truncate(pos= None) 剪掉 自pos位置之后的数据,返回新的文件长度(字节为单位)

4、文本文件操作模式:

模式字符:

't' (默认)

1. 默认文件中存储的数据为字符数据,以行为单位分隔,在python内部统一用'\n'作为换行符进行分隔;

2. 对文本文件的读写需要用字符串(str)进行读取和写入数据;

各操作系统的换行符:

linux 换行符:'\n'

whindows 换行符:'\r\n'

旧的macintosh 换行符:'\r'

新的Mac OS 换行符:'\r'

说明:

在文本文件模块下,各操作系统的换行符在读入python内部时办的为字符'\n';

defread_file_content():try:

f= open('info.txt')whileTrue:

s= f.readline() #'小张 20 100\n'

if nots:breaks2= s.strip() #去掉两端空白字符(#'小张 20 100')

name_age_score = s2.split() #['小张' '20' '100']

n, a, s = name_age_score #序列赋值

d = {'name': n, 'age': int(a), 'score': int(s)}

L.append(d)print(s)exceptOSError:print('打开文件失败')returnLif __name__ == '__main__':

docs=read_file_content()print(docs)

文件的迭代读取:

open返回的文件流对象是可迭代对象;

5、文本文件的写操作:

写文件模式有:

'w'

'x'

'a'

文件操作模式:

'r'以只读方式打开(默认)'w'以只写方式打开,删除原有文件内容(如果文件不存在,则创建该文件并以只写方式打开)'x' 创建一个新文件, 并以写模式打开这个文件,如果文件存在则会产生"FileExistsError"错误'a'以只写文件打开一个文件,如果有原文件则追加到文件末尾'b'用二进制模式打开't'文本文件模式打开 (默认)'+' 为更新内容打开一个磁盘文件 (可读可写)缺省模式是'rt'

'w+b'可以实现二进制随机读写,当打开文件时,文件内容将被清零'r+b'以二进制读和更新模式打开文件,打开文件时不会清空文件内容'r+' 以文本模式读和更新模式打开文件,打开文件时不会清空文件内容

6、二进制文件操作:

默认的文件中存储的都是以字节为单位的数据,通常有人为规则的格式,需要以字节为单位进行读写;

linux下#man ascii

ubuntu#xxd baidu.gif | head #ubuntu以十六进制方式查看图片(baidu.gif)

F.read() 的返回类型:

1.对于文本模式(’t')打开的文件,返回字符串str;

2.对于二进制模块('b')打开的文件,返回字节器bytes;

F.write(x)

1.对于文本模式,x必须为字符串;

2.对于二进制模块,x必须为字节串;

以十六进制方式查看 文件内容的命令:

# xxd 文件名 #以十六进制方式查看文件

#file_write_binary.py#示意以二进制方式写文件到’data.bin‘

try:

f= open('data.bin', 'wb')print('open 成功')#写入数据

b = b'\xe4\xb8\xad'f.write(b)

f.write(b'\x00\x00')

f.close()exceptOSError:print('file open fail')

str1= '15683359115'b= str1.encode('utf-8')

F.seek()方法:

F.seek(偏移量,相对位置)

偏移量:

大于0的数代表向文件尾方向移动;

小于0的数代表向文件头方向移动;

相对位置:

0代表从文件头开始偏移;

1代表从当前位置开始偏移;

2代表从文件尾开始偏移;

作用:

改变当前文件的读写位置;

注:seek 通常对 二进制模式打开的文件进行操作;

F.tell()方法:

作用:

返回当前文件读写位置;

小结:

文件操作的两种模式:

'b' 二进制模式

't' 文本模式

==检索指定目录,下所有后辍为Py的文件==

importosimportos.path#检索指定路径下,所有后辍为py的文件

ls =[]defgetAppointPathFile(path, ls):

filelist= os.listdir(path) #列出目录下所有文件包括子目录

try:for tmp infilelist:

pathTmp= os.path.join(path, tmp) #将路径与filelist组合

if True ==os.path.isdir(pathTmp):

getAppointPathFile(pathTmp, ls)#对子目录使用递归继续深入检索

elif pathTmp[pathTmp.rfind('.') + 1:].upper() == 'PY': #取文件后辍,变将后辍大写

ls.append(pathTmp)exceptPermissionError:pass

defmain():whileTrue:

path= input('请输入路径:').strip()if os.path.isdir(path) ==True:breakgetAppointPathFile(path, ls)for file inls:print(file)print(len(ls))

main()

回顾:

1.迭代器:it = iter(可迭代对象)

value = next(it) #从迭代器中获取值,当没有数据时触发StopIteration通知;

2.生成器:创建可迭代对象,提供动态生成数据对象;

生成器有两种:生成器函数和生成器表达式

生成器函数:

含有yield语句的函数是生成器函数

yield 表达式

yield作用: 是为next(it) 函数提供数据,生成器函数的执行流程和函数不同。

生成器表达式:(x ** 2 for x in range(10)) 注意与列表推导式区分开

3.迭代相关的函数:(也称生成器函数)

zip(iter1, iter2, iter3, .....) 返回一个zip对象,此对象用于生成一个元组,此元组中的元素分别由iter1,iter2可迭代对象中的元组构成(元组个数由最小的可迭代对象决定);

enumerate(iterable, start=0) 生成带索引的枚举对象,返回的迭代类型为索引-值对(index-value)对,默认索引从零开始,也可用start指定; 序号;

4.容器类 :字节串 bytes 字节数组 bytearray

5.str.encode(编码字符串) 转为bytes

bytes.decode(编码字符器) 转为str

1.文件 file 存储以字节为单位的数据;

文件的打开模式:二进制模式'b'文本模式't' 默认

文件的操作模式:读 'r' 写 'w', 'a'追加, 'x'文件存在报错,没有报错

F.close()

F.read(n=-1) /F.feadline() /F.readlines()

F.write(x) / F.writelines(列表)

F.seek(偏移量offset,起始位置whence)

F.tell() 获取当前读取位置

文件流对象是可迭代对象

压缩算法:zip unzip huffman

2.汉字编码:

GB18030(GBK(GB2312))

UNICODE32(UNICODE16) ---->UTF-8 (8-bit Unicode Tranfromation Fortat)

3.编码字符串

'gb18030' / 'gbk' / 'gb2312'

'utf-8'

'ascii'

4.编码注释:

#-*- coding: utf-8 -*-告诉解释器编码是什么utf-8

6>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值