Python核心数据类型——元组
元组对象(tuple)是序列,它具有不可改变性,和字符串类似。从语法上讲,它们便在圆括号中,它们支持任意类型、任意嵌套及常见的序列操作。
- 任意对象的有序集合:与字符串和列表类似,元组是一个位置有序的对象集合(内容维持从左到右的顺序),可以嵌入到任何类别的对象中。
- 通过偏移存取:同字符串、列表一样,在元组中的元素通过偏移(而不是键)来访问。支持基于偏移的操作。如索引和分片。
- 属于不可变序列类型:类似字符串,元组是不可变的,它们不支持应用在列表中任何原处修改的操作。
- 固定长度、异构、任何嵌套:元组不可变,在不生成一个拷贝的情况下不能增长或缩短。元组可以包含其他的复合对象(例如:列表、字典和其他元组等),支持嵌套。
- 对象引用的数组:元组最好看做是对象引用的数组。元组存储指向其他对象的存取点(引用),并且对元组进行索引操作的速度相对较快。
常见元组常量和运算
运算 | 解释 |
() | 空元组 |
T = (0,) | 单个元素的元组(非表达式) |
T = (0,’NI’,1.2,3) | 四个元素的元组,混合类型 |
T = 0,’Ni’,1.2,3 | 四个元素元组,与前列相同 |
T = (‘abs’,(‘def’,’ghi’)) | 嵌套元组 |
T = tuple(‘spam’) | 一个可迭代对象的项转换为元组 |
T[i],T[i][j],T[i:j],len(T) | 索引,索引的索引,分片,长度 |
T1+T2,T * 3 | 合并,重复(元素项重复) |
for x in T : print(x) | 迭代 |
‘spam’ in T | 成员关系 |
[x ** 2 for x in T] | 列表解析 |
T.index(‘Ni’) | 搜索 |
T.count(‘Ni’) | 计数 |
sorted(T) | 返回一个排序后的列表 |
>>> T = (1,2,3,4) >>> len(T) 4 >>> T + (5,6) (1, 2, 3, 4, 5, 6) >>> T[0] 1 >>> T.index(4) 3 >>> T.count(4) 1 >>> T[0] = 2 #元组是不可变的 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: ‘tuple‘ object does not support item assignment >>> T = (‘spam‘,3.0,[11,22,33]) >>> T[1] 3.0 >>> T[2][1] 22 >>> T.append(4) #不可增长或缩短 Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: ‘tuple‘ object has no attribute ‘append‘
元组确实支持字符串和列表的一般序列操作
>>> (1,2) + (3,4) #生成新的元组 (1, 2, 3, 4) >>> (1,2) * 4 #生成新的元组 (1, 2, 1, 2, 1, 2, 1, 2) >>> T = (1,2,3,4) >>> T[0],T[1:3] #生成新的元组 (1, (2, 3))
Python核心对象类型——文件
文件对象是Python代码计算机上外部文件的主要接口。虽然文件是核心类型,但它有些特殊:没有特定的常量语法创建文件。要创建一个文件对象,需要调用内置的open函数以字符串的形式传递给它一个外部的文件名以及一个处理模式的字符串。例如:创建一个文本输出文件,可以传递其文件名以及’w’处理模式字符串以写数据:
>>> f = open(‘data.txt‘,‘w‘) #当前文件夹下创建新文件 >>> f.write(‘Hello\n‘) #把hello字符串写入文件 6 >>> f.write(‘world\n‘) 6 >>> f.close() #关闭文件
在当前文件夹下创建了一个文件,并向它写入文本(文件名可以是完整的路径)。读取内容,以‘r’处理模式打开文件。
>>> f.open(‘data.txt‘,‘r‘) >>> text = f.read() >>> text ‘Hello\nworld\n‘ >>> print(text) Hello world >>> text.split() #文件内容为字符串 [‘Hello‘, ‘world‘]
常见文件运算
操作 | 解释 |
output = open(r’c:\spam‘,’w’) | 创建输出文件(‘w’是指写入) |
input = open(‘data’,’r’) | 创建输入文件(‘r’是指读取) |
input = open(‘data’) | 与上一行相同(‘r’是默认值) |
aString = input.read() | 把整个文件读取到变量 |
aStrint = input.read(N) | 读取之后的N个字节 |
aString = input.readline() | 读取下一行(包括末标识符) |
aList = input.readlines() | 读取整个文件到字符串列表 |
output.write(aString) | 写入字节字符到文件 |
output.writelines(aList) | 把列表内所有字符串写入文件 |
output.close() | 手动关闭文件(当文件手机完成时会替你关闭文件) |
output.flush() | 把输出缓冲区刷到硬盘中,但不关闭文件 |
anyFile.seek(N) | 修改文件位置到偏移量N出以便进行下一个操作 |
for line in open(‘data’):use line | 文件迭代器一行一行地读取 |
open(‘f.txt’,encoding=’latin-1’) | Unicode文本文件(str字符串) |
open(‘f.bin’,’rb’) | 二进制byte文件(bytes字符串) |
打开文件
为了打开一个文件,程序会调用内置函数open函数,首先是外部名,接着是处理模式。模式典型地用字符串’r’代表为输入打开文件(默认值),’w’代表为输出生成并打开文件,’a’代表为在文件尾部追加内容而打开文件。处理模式也可以指定为其他选项:
- 在模式字符串尾部加上b可以进行二进制数据处理(行末转换Unicode被关闭了)。
- 加上“+”意味着同时为输入和输出打开文件(也就是说,我们可以对相同文件对象进行读写,往往与文件中的修改的查找操作配合使用)
要打开的两个参数必须都是Python的字符串,第三个是可选参数,它能够用来控制输出缓存:传入“0”意味着输出无缓存(写入方法调用时立即传给外部文件)。外部文件参量可能包含平台特定的以及绝对或相对目录路径前缀。没有目录路劲时,表示存在当前的工作目录中(也就是脚本运行的地方)。
使用文件
一旦存在一个文件对象,就可以调用其方法来读写相关的外部文件。在任何情况下,Python程序中的文本文件都采用字符串的形式。读取文件是会返回字符串形式的文本,文本作为字符串传递给write方法。
- 文件迭代器是最好的读取性工具:虽然表中的读写方法都是常用的,但是要记住,现在从文本文件读取文字行的最佳方式是根本不要读取该文件。文件也有个迭代器会自动地在for循环,列表解析或者其他迭代语句中对文件进行逐行读取。
- 内容是字符串,不是对象:注意从文件读取的数据回到脚本时是一个字符串。如果字符串不是所需要的,就得将其转换成其他类型的对象。与print不同的是,当把数据写入文件时,Python不会自动把对象转换为字符串——必须传递一个已经格式化的字符串。
- close是通常选项:调用close方法将会终止对外部文件的连接。在Python中。一旦对象不再被引用,则这个对象的内存空间就会自动被收回。当文件对象被收回的时候,Python也会自动关闭该文件。这就意味着不需要总是手动去关闭文件,尤其是对于不会运行很长时间的简单脚本,另一方面,手动关闭调用没有任何坏处,而且在大型程序中通常是个很不错的习惯。严格的讲,文件的这个手机完成后自动关闭的特性不是语言定义的一部分,而且可能随时间而改变,因此,手动进行文件close方法调用是我们需要养成的一个好习惯。
- 文件是缓冲的并且是可查找的:关于关闭文件的提示很重要,因为关闭既释放了操作系统资源也清空了缓冲区。默认情况下,输出文件总是缓冲的,这意味着写入的文本可能不会立即自动从内存转换到硬盘——关闭一个文件,或者运行其flush方法,迫使缓冲的数据进入硬盘。可以有额外的open参数来避免缓存,但是,这可能会影响到性能。Python文件也是在字节偏移的基础上随机访问的,他们的seek方法允许脚本跳转到指定位置读取或写入。
简单列子:首先为输出而打开一个新文件,写入一个字符串(以终止符\n结束),之后关闭文件。接下来,我们将会在输入模式下再一次打开同一文件,读取该行。注意第二个readline调用返回一个空字符串。这是Python文件方法告诉我们已经到达文件底部(文件的空行是含有新行符的字符串,而不是空字符串):
>>> myfile = open(‘myfile.txt‘,‘w‘) >>> myfile.write(‘hello textfile\n‘) 15 >>> myfile.write(‘goodbye text file\n‘) 18 >>> myfile.close() >>> myfile = open(‘myfile.txt‘) >>> myfile.readline() ‘hello textfile\n‘ >>> myfile.readline() ‘goodbye text file\n‘ >>> myfile.readline() ‘‘
>>> open(‘myfile.txt‘).read() #一次性全部读取整个文件 ‘hello textfile\ngoodbye text file\n‘ >>> print(open(‘myfile.txt‘).read()) #友好的显示 hello textfile goodbye text file #如果想要一行一行地扫描一个文本文件,文件迭代器往往是最佳的选择 >>> for line in open(‘myfile.txt‘): ... print(line,end=‘‘) ... hello textfile goodbye text file
python3.0+中文本和二进制文件
文件类型都有open的第二个参数决定,模式字符串包含一个“b”表示二进制。python总是支持文本和二进制文件。二者之间的明显区别:
- 文本文件内容表示为常规的str字符串,自动执行Unicode(包括ACSII和其他的8位编码)编码和解码,并且默认执行末行转换。
- 二进制文件把内容表示一个特殊的bytes字符串类型,并且允许程序不修改地访问文件内容。
>>> data = open(‘data.bin‘,‘wb‘) >>> data.write(b‘\x00\x00\x00\x07spam\x00\x08‘) 10 >>> data.close() >>> data = open(‘data.bin‘,‘rb‘).read() >>> data b‘\x00\x00\x00\x07spam\x00\x08‘ >>> data[4:8] b‘spam‘ >>> data[4] 115 >>> bin(data[4]) ‘0b1110011‘
此外,二进制文件不会对数据执行任何末行转换;在根据转化写入和读取并实现Unicode编码的时候,文本文件默认地把所有形式和\n之间映射起来。
在文件中存储并解析python对象
需要注意的是,我们必须使用转换工具把对象转成字符串保存至文件中,写入方法不会自动地替我们做任何字符串格式转换工作。
>>> x,y,z = 43,44,45 >>> s = ‘spam‘ #字符串可以直接存至文件 >>> D = {‘a‘:1,‘b‘:2} >>> L = [1,2,3] >>> F = open(‘datafile.txt‘,‘w‘) >>> F.write(s + ‘\n‘) #添加换行符 5 >>> F.write(‘{0},{1},{2}\n‘.format(x,y,z)) #需要转换为字符串 9 >>> F.write(str(L) + ‘$‘ + str(D) + ‘\n‘) #需要转换为字符串 27 >>> F.close()
通过打开和读取文件查看内容返回的为字符串。使用print语句则会解释嵌行终止符显示友好结果:
>>> chars = open(‘datafile.txt‘).read() >>> chars "spam\n43,44,45\n[1, 2, 3]${‘b‘: 2, ‘a‘: 1}\n" >>> print(chars) spam 43,44,45 [1, 2, 3]${‘b‘: 2, ‘a‘: 1}
在真正的使用用过程中,读取文件后python不会自动把字符串转换为数字或其他类型的对象。我们不得不使用其他转换工具,把文本文件中的字符串转成真正的python对象。
>>> F = open(‘datafile.txt‘) >>> line = F.readline() >>> line ‘spam\n‘ >>> line.rstrip() #用rstrip方法去掉多余的终止符 ‘spam‘ >>> line ‘spam\n‘ >>> line[:-1]#或用分片去掉多余的终止符 ‘spam‘ >>> line = F.readline() >>> line ‘43,44,45\n‘ >>> parts = line.split(‘,‘) #用split方法从逗号中转换为列表 >>> parts [‘43‘, ‘44‘, ‘45\n‘] >>> int(parts[1]) 44 >>> parts = [int(p) for p in parts] #需要得到真正的整数类型,需要int函数转换 >>> parts [43, 44, 45] #还有一个方法可以用内置函数eval进行转换。eval函数能够把字符串当做可执行程序代码(从技术上讲,就是一个含有python表达式的字符串)。 >>> line = F.readline() >>> line "[1, 2, 3]${‘b‘: 2, ‘a‘: 1}\n" >>> parts = line.split(‘$‘) #split从$中转换为列表 >>> parts [‘[1, 2, 3]‘, "{‘b‘: 2, ‘a‘: 1}\n"] >>> eval(parts[0]) #eval函数可以把字符串转换为可执行代码 [1, 2, 3] >>> objects = [eval(p) for p in parts] >>> objects [[1, 2, 3], {‘b‘: 2, ‘a‘: 1}]
用pickle存储Python的原生对象
使用eval可以把字符串转换为对象,它是一个功能强大的工具,有时它太过于强大,只要权限足够,会执行python的任何表达式,甚至有可能会删除计算机上的所有文件的表达式。
如果真的要存储python原生对象,又无法信赖文件的数据来源,python标准库pickle模块会是个理想的选择。
pickle模块几乎能够存储任何python对象的高级工具,不用我们把字符串转换来转换去,也就是我们可以直接存储任何对象,从文件中取回时,仍然是之前保存时的对象。实际上,pickle是内部将对像转换为字符串形式,取回时pick自动重建对象。
>>> D = {‘a‘:1,‘b‘:2} >>> F = open(‘datafile.pkl‘,‘wb‘) >>> import pickle >>> pickle.dump(D,F) >>> F.close() >>> F = open(‘datafile.pkl‘,‘rb‘) >>> E = pickle.load(F) >>> E {‘b‘: 2, ‘a‘: 1}
注意:pickle程序创建和使用一个bytes字符串对象,意味着这些对象创建的是二进制模式文件。所以我们以二进制模式打开用来存储pickle化的对象的文件。
文件中打包位二进制数据的存储与解析
有些高级应用程序需要处理打包的二进制数据,这些数据可能是C语言程序生成的。Python标准库中包含一个能够在一范围起作用的工具:struct模块能够构造并解析打包的二进制数据。从某种意义上说,它是另一个数据转换工具,能够把文件中的字符串读为二进制数据。
例如:要生成一个打包的二进制数据文件,用‘wb’(写入二进制)模式打开,并将一个格式化字符串和几个python对象传给struct。这里用的格式化字符串是指一个4字节整数、一个包含4个字符的字符串以及一个2位整数的数据包,所有这些都按照高位在前(big-endian)的形式(其他格式代码能够处理补位字节、浮点数)。
##struct打包 >>> F = open(‘data.bin‘,‘wb‘) >>> import struct >>> data = struct.pack(‘>i4sh‘,7,b‘spam‘,8) #注意字符串必须是二进制b模式 >>> data b‘\x00\x00\x00\x07spam\x00\x08‘ >>> F.write(data) 10 >>> F.close() ##struct解包 >>> F = open(‘data.bin‘,‘rb‘) >>> data = F.read() >>> data b‘\x00\x00\x00\x07spam\x00\x08‘ >>> values = struct.unpack(‘>i4sh‘,data) >>> values (7, b‘spam‘, 8)
详情可以参考python库手册,或交互模式下dir和help函数查看
>>> dir(struct) [‘Struct‘, ‘__all__‘, ‘__builtins__‘, ‘__cached__‘, ‘__doc__‘, ‘__file__‘, ‘__lo ader__‘, ‘__name__‘, ‘__package__‘, ‘__spec__‘, ‘_clearcache‘, ‘calcsize‘, ‘erro r‘, ‘iter_unpack‘, ‘pack‘, ‘pack_into‘, ‘unpack‘, ‘unpack_from‘]
文件上下文管理器
文件上下文管理比文件自身多了一个异常处理功能,它允许我们把文件处理代码包装到一个逻辑层中,以确保在退出后可以自动关闭文件,而不是依赖于垃圾收集上的自动关闭:
with open(r’c:\misc\data.txt’) as myfile:
for line in myfile:
…..use line here…..
其他文件类工具
open函数能够实现在Python中编写的绝大多数文件处理。尽管更高级的任务,Python还有额外的类文件工具:管道、先进先出队列(FIFO)、套接字、通过键访问文件、对象持久、基于描述符的文件、关系数据库和面向对象数据库接口等。例如,描述符文件(descriptor file) 支持文件锁定和其他的底层工具,而套接字提供网络和进程间通信的接口。
- 标准流:在sys模块中预先打开的文件对象,例如:sys.stout
- os模块中的描述文件:处理整数文件,支持诸如文件锁定之类的较低级工具。
- socket、pipes和FIFO文件:文件类对象,用于同步进程或者通过网络进行通信。
- 通过键来存取的文件:通过键直接存储的不变的python对象。
- shell命令流:像os.popen和subprocess.Popen这样的工具,支持产生shell命令,并读取和写入到标准流。
检查代码对象类型
Python脚本中至少有3种方法可以做到代码对象类型检测:
>>> if type(L) == type([]): print(‘yes‘) ... yes >>> if type(L) == list: print(‘yes‘) ... yes >>> if isinstance(L,list): print(‘yes‘) ... yes