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函数,首先是外部名,接着是处理模式。
语法:
如: >>> fp = open(r'c:\data\user_data.txt','r') #以只读模式打开c:\data\user_data.txt文件
文件按指定模式打开后,通过文件句柄(如:fp)对文件内容进行操作。
处理模式典型地用字符串
- ’r’代表为只读打开文件(默认值)。
- ’w’代表为只写模式【不可读;当文件不存时,创建文件;当文件存在时,清空文件内容后再写】。
- ’a’代表为在文件尾部追加内容模式【可追加读写;当文件不存在时,创建后写内容;当文件存在时,在文件内容尾部追加内容】。
处理模式也可以指定为其他选项:
- 在模式字符串尾部加上b(byte)可以进行二进制数据处理(行末转换Unicode被关闭了),读取到的内容是字节类型,写入时也需要提供字节类型。
- ‘rb’
- ‘wb’
- ‘ab’
- 加上“+”意味着同时为输入和输出打开文件(也就是说,我们可以对相同文件对象进行读写,往往与文件中的修改的查找操作配合使用)
- ‘r+’:读写【可读,可写;注意不会创建不存在的文件;如果直接写文件,则从顶部开始写,覆盖之前此位置的内容;如果先读后写,则会在文件最后追加内容。】
- ‘w+’:可写读。当文件不存时,创建文件;当文件存在时,覆盖文件后再写;注意先覆盖文件(也就是空文件),后面使用读无意义了】
- ‘a+’:追加写读。从文件顶部读取内容,从文件底部添加内容,文件不存在则创建。
要打开的两个参数必须都是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}]
文件方法:
方法 | 描述 |
fileObject.close() | close() 方法用于关闭一个已打开的文件。关闭后的文件不能再进行读写操作, 否则会触发 ValueError 错误。 close() 方法允许调用多次。当 file 对象,被引用到操作另外一个文件时,Python 会自动关闭之前的 file 对象。 使用 close() 方法关闭文件是一个好的习惯。 |
fileObject.flush() | flush() 方法是用来刷新缓冲区的,即将缓冲区中的数据立刻写入文件,同时清空缓冲区,不需要是被动的等待输出缓冲区写入。一般情况下,文件关闭后会自动刷新缓冲区,但有时你需要在关闭前刷新它,这时就可以使用 flush() 方法。 |
fileObject.fileno() | fileno() 方法返回一个整型的文件描述符(file descriptor FD 整型),可用于底层操作系统的 I/O 操作。 |
fileObject.isatty() | isatty() 方法检测文件是否连接到一个终端设备,如果是返回 True,否则返回 False。 |
fileObject.next() | next() 方法在文件使用迭代器时会使用到,在循环中,next()方法会在每次循环中调用,该方法返回文件的下一行,如果到达结尾(EOF),则触发 StopIteration |
fileObject.read([size]) | read([size]) ,size为数值,方法用于从文件读取指定的字符数【无b模式时】或字节数【加上b模式时】,如果size未给定或为负则读取所有。 |
fileObject.readline() | readline() 方法用于从文件读取整行,包括 "\n" 字符。如果指定了一个非负数的参数,则返回指定大小的字节数,包括 "\n" 字符。 |
fileObject.readlines( sizehint ) | readlines() 方法用于读取所有行(直到结束符 EOF)并返回列表,若给定sizeint>0,返回总和大约为sizeint字节的行, 实际读取值可能比sizhint较大, 因为需要填充缓冲区。如果碰到结束符 EOF 则返回空字符串。sizehint -- 从文件中读取的字节数/字符数。 |
fileObject.seek(offset[, whence]) | seek() 方法用于移动文件读取指针到指定位置。offset -- 开始的偏移量,也就是代表需要移动偏移的字节数。whence:可选,默认值为 0。给offset参数一个定义,表示要从哪个位置开始偏移;0代表从文件开头开始算起,1代表从当前位置开始算起,2代表从文件末尾算起。 |
fileObject.tell(offset[, whence]) | tell() 方法返回文件的当前位置,即文件指针当前位置。 |
fileObject.truncate( [ size ]) | truncate() 方法用于截断文件,如果指定了可选参数 size,则表示截断文件为 size 个字符。 如果没有指定 size,则从当前位置起截断;截断之后 size 后面的所有字符被删除。size -- 可选,如果存在则文件截断为 size 字节。 |
fileObject.write( [ str ]) | write() 方法用于向文件中写入指定字符串。在文件关闭前或缓冲区刷新前,字符串内容存储在缓冲区中,这时你在文件中是看不到写入的内容的。str -- 要写入文件的字符串。 |
fileObject.writelines( [ str ]) | writelines() 方法用于向文件中写入一序列的字符串。这一序列字符串可以是由迭代对象产生的,如一个字符串列表。换行需要制定换行符 \n。str -- 要写入文件的字符串序列。 |
用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 fp: for line1 in fp: "...use line here..."
python2.7及以后版本,还可以同时打开多个文件:
with open(r'c:\misc\data1.txt') as fp1 , open(r"c:\misc\data1.txt") as fp2,.....: for line1 in fp1: "...use line here..." for line2 in fp2: "...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