Python之输入和输出
Python学习笔记之八输入和输出:展现程序的输出有多种方法,可以打印成我们可读的形式,也可以写入到文件以便后面使用。
格式化输出
输出值的方法有几种:
1. 表达式语句(有些表达式会返会一个结果,就是输出值)
2. print()函数
3. 文件对象的write() 方法,标准输出文件可以引用sys.stdout ,这在Python的库参考手册中有。
设置字符串输出格式的方法有两种:
第一种是使用字符串切片和连接操作以及字符串本身的一些方法自己做字符串处理,并按照特定的格式输出;
第二种方法是使用 str.format() 方法
string 模块包含一个Template 类,提供另外一种向字符串代入值的方法。
Python 通过repr() 和str() 函数可以将任何值转换为字符串
str() 函数的用意在于返回对于我们更加友好的表现形式,而repr() 的用意在于生成对于解释器可读的表现形式,如果转换不成功将会引发SyntaxError 异常。对于我们如果没有特别的表现形式,str()和repr() 将返回相同的值(一般情况下返回的值都是相同的)。许多值,例如数字或者列表和字典这样的结构,使用这两个中的任意一个都具有相同的表示形式。字符串会相对特殊一些,有两种不同的表示形式:
一些例子:
>>> s = 'Hello, world.' >>> str(s) 'Hello, world.' >>> repr(s) "'Hello, world.'" >>> str(1/7) '0.14285714285714285' >>> x = 10 * 3.25 >>> y = 200 * 200 >>> s = 'The value of x is ' + repr(x) + ', and y is ' + repr(y) + '...' >>> print(s) The value of x is 32.5, and y is 40000... >>> # The repr() of a string adds string quotes and backslashes: ... hello = 'hello, world\n' >>> hellos = repr(hello) >>> print(hellos) 'hello, world\n' >>> # The argument to repr() may be any Python object: ... repr((x, y, ('spam', 'eggs'))) "(32.5, 40000, ('spam', 'eggs'))"
这里用两种方法输出平方和立方表:
>>> for x in range(1, 11): ... print(repr(x).rjust(2), repr(x*x).rjust(3), end=' ') ... # Note use of 'end' on previous line ... print(repr(x*x*x).rjust(4)) ... 1 1 1 2 4 8 3 9 27 4 16 64 5 25 125 6 36 216 7 49 343 8 64 512 9 81 729 10 100 1000 >>> for x in range(1, 11): ... print('{0:2d} {1:3d} {2:4d}'.format(x, x*x, x*x*x)) ... 1 1 1 2 4 8 3 9 27 4 16 64 5 25 125 6 36 216 7 49 343 8 64 512 9 81 729 10 100 1000
(注意:在第一个示例中,每列之间的一个空格由print() 自动添加:print() 函数总会在它的参数之间添加空格.)
上面的例子演示了字符串对象的str.rjust()方法,它通过在左侧填充空格使字符串在给定的宽度的列右对齐。类似的方法还有str.ljust()和str.center()。 这些方法会返回新的字符串。如果输入的字符串太长,他们不会截断字符串,而是保持原样返回,但会使格式变的混乱,如果要截断字符串,可以加一个切片操作,例如x.ljust(n)[:n]。
另外一种方法 str.zfill(),它向数值字符串左侧填充零。该函数可以正确识别正负号:
>>> '12'.zfill(5) '00012' >>> '-3.14'.zfill(7) '-003.14' >>> '3.14159265359'.zfill(5) '3.14159265359'
如果字符串长度的值小于zfill() 参数的值,那么就会在数值字符串前面补零,如果字符串长度的值大于或等于zfill() 参数的值,那么它就保持原样。
str.format()方法的基本用法如下所示:
>>> print('We are the {} who say "{}!"'.format('knights', 'Ni')) We are the knights who say "Ni!"
花括号及其中的字符(称为格式字段)将被替换为传递给str.format()方法的对象。可以用括号中的数字指定传递给str.format()方法的对象的位置。
>>> print('{0} and {1}'.format('spam', 'eggs')) spam and eggs >>> print('{1} and {0}'.format('spam', 'eggs')) eggs and spam
如果str.format()方法使用关键字参数,那么将通过参数名引用它们的值。
>>> print('This {food} is {adjective}.'.format( ... food='spam', adjective='absolutely horrible')) This spam is absolutely horrible.
位置参数和关键字参数可以随意组合:
>>> print('The story of {0}, {1}, and {other}.'.format('Bill', 'Manfred', other='Georg')) The story of Bill, Manfred, and Georg.
‘!a’(应用ascii()),’!s’(应用str())和’!r’(应用repr())可以用来格式化之前对值进行转换。
>>> import math >>> print('The value of PI is approximately {}.'.format(math.pi)) The value of PI is approximately 3.14159265359. >>> print('The value of PI is approximately {!r}.'.format(math.pi)) The value of PI is approximately 3.141592653589793.
上面我们看到
print('{0:2d} {1:3d} {2:4d}'.format(x, x*x, x*x*x)
{2:2d} 第一个是第几个参数,第二个的2d 是这个参数的类型,下面的例子是将Pi 转为三位精度。
>>> import math >>> print('The value of PI is approximately {0:.3f}.'.format(math.pi)) The value of PI is approximately 3.142.
‘:’ 后面紧跟一个整数可以限定该字段的最小宽度。这在美化表格时使用:
>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678} >>> for name, phone in table.items(): ... print('{0:10} ==> {1:10d}'.format(name, phone)) ... Jack ==> 4098 Dcab ==> 7678 Sjoerd ==> 4127
如果有一个实在很长的格式字符串但又不想分开,要是可以按照名字而不是位置引用变量就好了。有个简单的方法,可以传入一个字典,然后使用’[]’访问。
>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678} >>> print('Jack: {0[Jack]:d}; Sjoerd: {0[Sjoerd]:d}; ' ... 'Dcab: {0[Dcab]:d}'.format(table)) Jack: 4098; Sjoerd: 4127; Dcab: 8637678
也可以用’**’ 标志将这个字典以关键字的参数的方式传入。
>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678} >>> print('Jack: {Jack:d}; Sjoerd: {Sjoerd:d}; Dcab: {Dcab:d}'.format(**table)) Jack: 4098; Sjoerd: 4127; Dcab: 8637678
这种方式与内置函数vars() 组合起来将更加有用,该函数返回一个包含所有局部变量的字典。
旧式的字符串格式
??%运算符也可以用于字符串格式化。它将左边类似sprintf()-风格的参数应用到右边的参数,然后返回这种格式化操作生成的字符串。例如:
>>> import math >>> print('The value of PI is approximately %5.3f.' % math.pi) The value of PI is approximately 3.142.
读写文件
open()返回一个文件对象,最常见的用法带有两个参数:open(filename, mode)。
>>> f = open('workfile', 'w')
??第一个参数是一个含有文件名的字符串(文件有后缀的话要带上后缀)。第二个参数也是一个字符串,含有描述如何使用该文件的几个字符。mode 为’r’ 时表示只是读取文件;w 表示只是写入文件(已经存在的同名文件将被删掉);’a’表示打开文件进行追加,写入到文件中的任何数据将自动添加到末尾。
‘r+’表示打开文件进行读取和写入。mode 参数是可选的,默认为’r’。
??通常,文件以文本打开,这意味着,从文件读出和向文件写入的字符串会被特定的编码方式(默认是UTF-8)编码。模式后面的’b’ 以二进制模式打开文件:数据会以字节对象的形式读出和写入。所有不包含文本的文件最好都用这种二进制模式打开文件。
??在文本模式下,读取时默认会将平台有关的行结束符(Unix上是\n, Windows上是\r\n)转换为\n。在文本模式下写入时,默认会将出现的\n转换成平台有关的行结束符。这种修改对于ASCII 文本文件没有问题,但会损坏JPEG或EXE 这样的二进制文件中的数据。使用二进制模式读写此类文件时要特别小心。
文件对象的方法
假设文件对象f已经创建。
要读取文件内容,可以调用f.read(size),该方法读取若干数量的数据并以字符串或字节对象返回。size 是可选的数值参数。当size 被省略或者为负数时,将会读取并并返回整个文件;不过最好不要超过机器的内存,否者至多读取和返回size 大小的字节数据。如果到了文件末尾,f.read() 会返回一个空字符串(”)。
>>> f.read() 'This is the entire file.\n' >>> f.read() ''
注意:读取文件内容是一个字节一个字节从文件头读到文件未,一旦读完了,不会再从头开始,如果还要再用这个文件对象,只能是先把文件关闭,然后重新打开,把文件对象重新赋给这个文件对象,才能做其他操作
??f.readline()从文件读取一行数据;字符串结尾会带有一个换行符 (\n) ,只有当文件最后一行没有以换行符结尾时才会省略。这样返回值就不会有混淆,如果f.readline() 返回一个空字符串,那就表示已经达到文件的末尾了。而如果返回一个只包含一个换行符的字符串’\n’,则表示遇到了一个空行,也可以循环遍历文件对象来读取文件中的每一行:
>>> s = open('fibo.py','r') >>> s.readline() '#Fibonacci numbers module\n' >>> for line in s: ... print(line,end='') ... def fib(n): #write Fibonacci series up to n a,b = 0,1 while b < n: print(b,end=' ') a,b = b,a+b print() def fib2(n): #return Fibonacci series up to n result = [] a,b = 0,1 while b>>
如果想把文件中的所有行读到一个列表中,可以使用 list(f) 或 f.readlines()。
>>> lst1=[] >>> s = open('filetest.txt','r') >>> lst1=list(s) >>> lst1 ['This is the first line of the file.\n', 'This is the second line of the file.\n', 'This is the end line of the file\n'] >>> s.close() >>> lst2 = [] >>> s = open('filetest.txt','r') >>> lst2 = s.readlines() >>> lst2 ['This is the first line of the file.\n', 'This is the second line of the file.\n', 'This is the end line of the file\n'] >>>s.close()
f.write(string) 将string 的内容写入文件中并返回写入的字节的数目(这里不是追加,是覆盖)。
>>> s = open('filetest.txt','w') >>> s.write('This is a write test\n') 21 >>> s.close() >>> s = open('filetest.txt','r') >>> for line in s: ... print(line,end='') ... This is a write test >>>
如果想写入非字符串数据,需要先将它转换为字符串:
>>> f = open('filetest.txt','w') >>> value = ('the answer',42) >>> s = str(value) >>> s "('the answer', 42)" >>> f.write(s) 18 >>> f.close() >>> f = open('filetest.txt','r') >>> for line in f: ... print(line) ... ('the answer', 42) >>>
f.tell()返回一个给出文件对象在文件中当前位置的整数,在二进制模式下表示自文件开头的字节数:
>>> f.close() >>> f = open('filetest.txt','r') >>> f.readline() "('the answer', 42)" >>> f.tell() 18
若要更改文件对象的位置,可以使用 f.seek(offset,from_what). 新的位置由参考点(from_what)加上offset 计算得来。from_what 值为0表示以文件的开头为参考点,1 表示以当前的文件位置为参考点,2 表示以文件的结尾为参考点。 from _what 可以省略,默认值为0,表示以文件的开头作为参考点。
>>> f.close() >>> f1 = open('filetest.txt','r+') >>> f1.write('0123456789abcdef') 16 >>> f1.tell() 16 >>> f1.seek(0) 0 >>> f1.seek(4) 4 >>> f1.read(2) '45' >>> f1.seek(10) 10 >>> f1.read(1) 'a'
注意这里位置的修改一定要计算好是否在文件中的内容之内
>>> f1.seek(-2,2) Traceback (most recent call last): File "", line 1, in io.UnsupportedOperation: can't do nonzero end-relative seeks >>>
这样也是不行的
在文本文件中(没有以b模式打开),只允许从文件头开始寻找(有个例外是用seek(0,2) 寻找文件的末尾处),而且合法的偏移量只能是 f.tell() 返回的值或者是零。其它任何偏移值都会产生未定义的行为。
使用完一个文件后,调用f.close() 可以关闭它并释放其占有的所有系统资源。调用f.close() 后,如果再尝试使用该文件对象的会报错误。
>>>f1.close() >>> f1.read() Traceback (most recent call last): File "", line 1, in ValueError: I/O operation on closed file
使用with 关键字能够使文件用完后自动关闭。
>>> with open('filetest.txt','r') as f: ... read_data = f.read() ... >>> read_data '0123456789abcdef2)' >>> f.closed True
可以看到最后文件被关闭。
文件对象还有一些不太常用的方法,例如isatty()和truncate();有关文件对象的完整指南,请参阅 Python 库参考手册。
使用json 存储结构化数据
从文件中读写字符串相对容易,但对于数值来说比较麻烦,因为read()方法只会返回字符串,应将其传入int() 这样的函数,将’123’ 这样的字符串转换为对应的数值123. 但想要保存更为复杂的数据类型,例如嵌套的列表和字典,手工解析和序列化它们将变得更复杂。
Pyhon 允许使用常用的数据交换格式JSON(JavaScript Object Notation)。标准模块json 可以接受Python 数据结构,并将它们转换为字符串表示形式;此过程称为序列化。从字符串表示形式重新构建数据结构称为反序列化。序列化和反序列化的过程,表示该对象的字符串可以存储在文件或数据中,也可以通过网络连接传送给远程的机器。
注:JSON格式经常用于现代应用程序中进行数据交换。
如下是用简单的一行代码查看其JSON 字符串表示形式:
import json >>> x = [1,'simple','list'] >>> json.dumps(x) '[1, "simple", "list"]'
dumps() 函数的另外一个变体dump(),直接将对象序列化到一个文本文件,下面例子中x 是上面的列表对象,f 是为写入而打开的一个文本文件对象。
>>> f = open('filetest.txt','r+') >>> json.dump(x,f) >>> f.close() >>> f = open('filetest.txt','r') >>> for line in f: ... print(line) ... [1, "simple", "list"] >>>
如果f 是为读取而打打开的文本文件对象,需要重新解码对象(相当于是反序列化,就是把字符串还原成对象)
>>> f.close() >>> f = open('filetest.txt','r') >>> x[:] = json.load(f) >>> x [1, 'simple', 'list']
这种简单的序列化技术可以处理列表和字典,但序列化任意实例为JSON需要专门的技术,JSON模块的手册有详细的解释。
另参阅 pickle-pickle 模块
与JSON 不同,pickle 是一个协议,它允许任意复杂的Python 对象的序列化。 因此,它只用于 Python 而不能用来与其他语言编写的应用程序进行通信。默认情况下它并不安全。