一:文件
1.简介:内置open 函数会创建一个python 文件对象,可以作为计算机上的一个文件链接。在调用open 之后,可以通过调用返回文件对象的方法来读写相关外部文件。文件对象只是常见文件处理任务输出模块。
2,打开文件:为了打开一个文件,程序会调用内置open 函数,首先是外部名,接着是处理模式。模式典型地用字符串“r” 代表读文件,“w” 代表以写模式打开文件,“a” 代表在文件末尾追加内容而打开文件。同时,在模式字符串尾部加上 b 可以进行二进制数据处理,加上“+” 意味着同时为输入和输出打开文件。
3,使用文件:一旦存在一个文件对象,就可以调用其方法来读写相关的外部文件。注意,在任何情况下,Python 程序中的文本文件都采用字符串的形式。读取文件时会返回字符串形式的文本,文本作为字符串传递给 write 方法。
a) 文件迭代器是最好的读取行工具:现在从文本文件读取文字行的最佳方式是根本不要读取该文件。文件也有个迭代器会自动地在for 循环、列表解析或其它方式对文件进行逐行读取。
b) 内容是字符串,不是对象:注意从文件读取的数据回到脚本时是一个字符串。所以如果字符串不是你所需的,就得将其转换成其他类型的python 对象。当我们写入文件时,python 不会把对象自动转换为字符串------你必须传递一个已经格式化的字符串。str() 也许会派上用场。另外,Python 也包括一些高级标准库工具,它用来处理一般对象的存储(如 pickle 模块)以及处理文件中打包的二进制数据(例如,struct 模块)。
c) close 是通常选项:调用 close 方法将会终止对外部文件的连接。通常手动关闭没有任何坏处,而且这是个不错的习惯。
d)文件是缓冲的并且是可查找的:前面提到过手动关闭文件,因为这样既释放了操作系统资源也清空了缓冲区。默认情况下,输出文件总是缓冲的,这就是说,写入的文本不可能立即自动从内存转换到硬盘------关闭一个文件,或者允许其 flush 方法,迫使缓存的数据进入硬盘。同时,python 文件也是在字节偏移的基础上随机访问的,它们的seek 方法允许脚本跳转到指定的位置读取或写入。
二:实际应用中的文件:
1,注意write 方法不会为我们添加行终止符,所以程序必须包含它来严格地终止行。如果想要显示带有转义字符解释的文件内容,用对象的read 方法把整个文件读入到一个字符串中,并打印它:
>>> myfile = open(r'D:\test\myfile.txt','w')
>>> myfile.write('hello text file\n')
16
>>> myfile.write('goodbye text file\n')
18
>>> myfile.close
<built-in method close of _io.TextIOWrapper object at 0x02A7BC30>
>>> myfile = open(r'D:\test\myfile.txt','r')
>>> myfile.readline()
'hello text file\n'
>>> myfile.readline()
'goodbye text file\n'
>>> myfile.readline() #已经到达文件末尾
''
用read 方法和print 的形式:
>>> file = open(r'D:\test\myfile.txt','r')
>>> file.read()
'hello text file\ngoodbye text file\n'
>>> print(file.read()) #print 解释了转义字符的含义
hello text file
goodbye text file
如果想要一行一行地扫描一个文本文件,文件迭代器往往是最佳选择:
>>> for line in open(r'D:\test\myfile.txt','r'):
... print(line,end = '') #end = ' ' 意思为不换行
...
hello text file
goodbye text file
2,Python 3.0 中的文本和二进制文件:上述实例中使用了文本文件,在3.0 和 2.6 版本中,文件类型都是由open 的第二个参数决定,模式字符串包含一个”b“ 表示二进制。python 中总是支持文本文件和二进制文件,但是在python 3.0 中,二者之间没有明显的区别:
a) 文本文件把内容表示为常规的 str 字符串,自动执行Unicode 编码和解码,并且默认执行末行转换。
b) 二进制文件把内容表示为一个特殊的bytes 字符串类型,并且允许程序不修改的访问文件内容。
Note:如果需要处理国际化应用程序或者面向字节的数据,Python 3.0 中的区别会影响到代码。通常,你必须使用bytes 字符串处理二进制文件,并且用常规的 str 字符串处理文本文件。不能以文本模式打开一个二进制文件。
3,在文件中存储并解析Python 对象:
注意,当我们写入文件的时候,一定要将内容转换为字符串,因为写入方法不会自动地替我们做任何向字符串格式转换的工作。
>>> chars = open(r'D:\test\datafile.txt','r')
>>> chars.read()
"spam\n43,44,45\n[1, 2, 3]${'a': 1, 'b': 2}\n"
4,rstrip() 函数和 split() 函数用例:
>>> line = 'end '
>>> line.rstrip() #字符串 rstrip() 方法去掉多余的行终止符
'end'
>>> line = '43,44,45\n'
>>> line.split(',') #字符串 split() 方法,用逗号断开整行,返回字符串列表
['', '', '45\n']
对于存储 的列表和字典,我们可以运行 eval() 这一内置函数,eval() 能够把字符串当作可执行程序代码。也可以用来执行字符串表达式,并返回表达式的值:
>>> parts
['[1,2,3]', "{'a':1,'b':2}\n"]
>>> eval(parts[0]) #eval() 函数把字符串对象转化为对象
[1, 2, 3]
5,用pickle 存储Python 的原生对象:使用 eval() 可以把字符串转换为对象。事实上,eval() 有时会太过于强大。eval() 会高高兴兴地执行 python 的任何表达式,甚至是有可能会删除计算机上的所有文件的表达式,只要给予必要的权限。如果想要存储 Python 原生对象,但又无法信赖文件数据的来源,Python 标准库pickle 模块会是个理想的选择。pickle 模块是能够让我们直接在文件中存储几乎任何python 对象的高级工具,也并不需要求我们把字符串转来转去。例如,如果想要在文件中存储字典,就直接用pickle 来存储:
>>> D = {'a':1,'b':2}
>>> F = open(r'D:\test\datafile.pkl','wb') #二进制写入模式打开
>>> import pickle #导入pickle包
>>> pickle.dump(D,F) #把字典D存入文件F
>>> F.close()
>>> F = open(r'D:\test\datafile.pkl','rb') #二进制读出模式打开
>>> E = pickle.load(F) #将文件中的内容读出
>>> E
{'a': 1, 'b': 2}
pickle 模块执行所谓的对象序列化,也就是对象和字节字符串之间的相互转换。但我们要做的工作却很少。事实上,pickle 内部将字典转成字符串形式。例如
>>> open(r'D:\test\datafile.pkl','rb').read()
b'\x80\x03}q\x00(X\x01\x00\x00\x00aq\x01K\x01X\x01\x00\x00\x00bq\x02K\x02u.'
Note:我们用二进制模式打开用来存储pickle化的对象的文件,因为pickle程序创建和使用一个bytes 字符串对象,并且这些对象意味着二进制模式文件(文本模式文件意味着str 字符串)。
6,文件中打包二进制数据的存储与解析:struct 模块能够构造并解析打包的二进制数据。从某种意义上说,它是另一个数据转换工具,它能够把文件中的字符串解读为二进制数据。例如,要生成一个打包的二进制数据文件,用 'wb'(二进制写入)模式打开它,并将一个格式化字符串和几个Python 对象传给 struct。如下:
>>> F = open(r'D:\test\data.bin','wb') #用‘wb’打开
>>> import struct
>>> data= struct.pack('ii',7,8) #打包写入数据(‘ii’ 为数据格式)
>>> data
b'\x07\x00\x00\x00\x08\x00\x00\x00' #十六进制转义的格式进行打印
>>> F.write(data) #数据写入文件F
8
>>> F.close()
>>> F = open(r'D:\test\data.bin','rb') #用‘rb’进行读取
>>> data = F.read()
>>> data
b'\x07\x00\x00\x00\x08\x00\x00\x00'
>>> values = struct.unpack('ii',data) #用相同的格式进行解压缩
>>> values
(7, 8)
7,上下文管理器:比文件多了一个异常处理的功能,它不允许我们把文件处理代码包装到一个逻辑层中,以确保在退出后可以自动关闭文件,而不是依赖于垃圾收集上的自动关闭。
三:其他文件工具:
1,seek() 函数能够复位你在文件中的当前位置(下次读写将应用在该位置上),flush 能够强制性地将缓存输出写入磁盘(文件总会默认进行缓冲)等。
2,需要注意的是,虽然open() 函数及其返回的文件对象是 Python 脚本中通向外部文件的主要接口,Python 中还有其他类似的文件工具,例如:
a) 标准流:在sys 模块中预先打开的文件对象,例如 sys.stdout
b) os 模块中的描述文件:
c) sockets,pipes 和 FIFO 文件:文件类对象,用来同步进程或者通过网络进行通信。
d) 通过键来存取的文件:
e) Shell 命令流
四:重访类型分类:
1,共享操作:字符串、列表、元组都共享合并、长度、索引等序列操作。
2,只有可变对象(列表、字典、集合)可以原处修改;我们不能修改数字、字符串、串或者元组。
3,Python 中的bytearray 字符串类型是可变的。
4,frozenset 是集合的一个不可变的版本。
五:对象灵活性:
1,列表、字典和元组可以包含任何种类的对象。
2,列表、字典和元组可以任意嵌套。
3,列表和字典可以动态地扩大和缩小。
六:引用 VS 拷贝:
1,赋值操作总是存储对象的引用,而不是这些对象的拷贝。不过,因为赋值操作会产生相同对象的多个引用,需要意识到在原处修改可变对象时可能会影响程序中其他地方对相同对象的引用。如果你不想这么做,就需要明确地告诉Python 复制该对象。
>>> x = [1,2,3]
>>> L = ['a',x,'b'] #L和D共享x列表
>>> D = {'X':x,'y':2}
>>> x[1] = 'surprise' #改变共享列表对象
>>> L
['a', [1, 'surprise', 3], 'b'] #L和D也会改变
>>> D
{'X': [1, 'surprise', 3], 'y': 2}
>>>
2,如果你需要在途中产生拷贝,下面是拷贝的几种方法:
a) 没有限制条件的分片表达式 (L[ : ])能够复制序列。
b) 字典copy() 方法(X.copy())能够复制字典。
c) 有些内置函数 (例如,list)能够生成拷贝
d) copy 标准库模块能够生成完整拷贝。(深度拷贝)
3,拷贝需要注意的是,我们可以通过对原始列表进行分片而不是简单的命名操作来避免引用的副作用:
>>> x = [1,2,3]
>>> L = ['a',x[:],'b'] #利用分片生成一个新的对象,对L和D做修改不会影响x
>>> D = {'X':x[:],'y':2}
4,另外,对拷贝还需要注意:无条件值的分片以及字典copy 方法只能做顶层复制。也就是说,不能够复制嵌套的数据结构。如果需要一个完整的、完全独立的拷贝,那么就要使用标准的copy模块-----包括import copy 语句,并编辑 X = copy.deepcopy(Y) 对任意嵌套对象Y做完整的复制。这一调用语句能够递归地遍历对象来复制它们所有的组成部分。
七:比较、相等值和真值:
1,所有的 Python 对象也可以支持比较操作---测试相等性、相对大小等。当嵌套对象存在时, Python 能够自动遍历数据结构,从左到右递归地应用比较。
>>> L1 = [1,('a',3)]
>>> L2 = [1,('a',3)]
>>> L1 == L2 # ‘==’ 测试值的相同性
True
>>> L1 is L2 # ‘is’ 测试对象的一致性(是否在同一个内存地址中)
False
注意,如果时短字符串会出现什么情况:
>>> s1 = 'spam'
>>> s2 = 'spam'
>>> s1 == s2
True
>>> s1 is s2
True
这是因为在Python 内部暂时存储并重复使用短字符串作为最佳化,事实上内存里只有一个字符串‘spam’供 s1 和s2 分享。
2,Python 中不同类型的比较方法如下:
a)数字通过相对大小进行比较
b)字符串是按照字典排序,一个字符一个字符地对比进行比较
c)列表和元组从左到右对每部分的内容进行比较
d)字典通过排序之后(键、值)列表进行排序。
3,在python 3.0 中,字典的大小比较删除了,替代方案:要么编写循环来根据键比较值,要么手动比较排序的键/值列表------items 字典方法和内置的sorted()足够了:
>>> D1 = {'a':1,'b':2}
>>> D2 = {'a':1,'b':3}
>>> D1 == D2
False
>>> D1 < D2 #字典之间不支持比较
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'dict' and 'dict'
>>> list(D1.items())
[('a', 1), ('b', 2)]
>>> sorted(D1.items()) #用sorted()对items 进行排序
[('a', 1), ('b', 2)]
>>> sorted(D1.items()) < sorted(D2.items())
True
八:Python 中真和假的含义:
1,数字如果非零,则为真;
2,其他对象如果非空,则为真;
3,None对象: None,总被认为是假。这是Python 中一种特殊数据类型的惟一值,一般都起到一个空的占位符作用,与C语言中的NULL指针类似;
Note: None 不是意味着“未定义”,也就是说,None 是某些内容,而不是没有内容(尽管起名字是没有内容)----它是一个真正的对象,并且有一块内存,有python 给定一个内置的名称。
4,bool 类型: Python 也提供了一个内置函数bool,它可以用来测试一个对象的布尔值:>>>bool(1) >>>True
5,Type 对象:对内置函数 type(X),能够返回对象X 的类型对象,此外,python 3.0 中的类型标准库模块同样提供其他不能作为内置类型使用类型的名称,而且用 isinstance() 函数进行类型测试也是可能的。例如:
True
>>> type([1]) == type([])
True
>>> type([1]) == list
True
>>> isinstance([1],list)
True
isinstance(object,class):用来判断对象是不是和指定类型相同,若相同,返回True;
九:Python 中的其它类型
1,赋值生成引用,而不是拷贝;
2,重复能够增加层次深度:
>>> L = [1,2,3]
>>> X = L *4
>>> Y = [L] * 4
>>> X
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
>>> Y
[[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]
由于L在第二次重复中是嵌套的,Y结束嵌套的引用,返回赋值为L的原始列表。
>>> L = [4,5,6]
>>> X = L * 4 #未共享引用L,L改变不影响X
>>> Y = [L] * 4 #共享引用L,L改变影响Y
>>> L[1] = 0
>>> X
[4, 5, 6, 4, 5, 6, 4, 5, 6, 4, 5, 6]
>>> Y
[[4, 0, 6], [4, 0, 6], [4, 0, 6], [4, 0, 6]]
3,留意循环数据结构:如果遇到一个复合对象包含指向自身的引用,就称之为循环对象。
>>> L = ['grail']
>>> L.append(L) #自身引用自身
>>> L
['grail', [...]]
4,不可变类型不可以在原处改变:如果需要的化,可以通过分片、合并等操作来创建一个新的对象,再向后赋值给原引用。
>>> T = (1,2,3)
>>> T[2] = 4 #不能原地修改元组
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> T = T[:2] + (4,) #可以通过分片和合并操作创建一个新对象
>>> T
(1, 2, 4)