跟着官网学Python(8):输入输出
“Python输入、输出、文件读写以及异常知识。”
01 面临问题
继续跟着官网学Python,第7章输入输出。
前面已经基本学完Python的语法部分,也学会如何使用轮子,但是编程语言不能只在虚拟世界玩,需要与现实世界进行交互。
需要接受输入,理解用户指令,需要美好输出,让用户更好理解。
前面学习字符串的时候使用了print
,也强调了格式化输出。
那么本章在更全面的分享一下Python的输入与输出。
02 怎么办
有多种方法可以显示程序的输出,数据可以以人类可读的形式打印出来,或者写入文件以供将来使用。
更漂亮的输出的格式
前面遇到两种输出值的方法:表达式语句和print()
。比如输入1+1,会直接输出2。
很多时候,我们需要控制输出的格式,比如小数点后位数、首字母是否大写、对齐、日期格式等等,这里列出一些常见的格式化方法:
- 使用格式化字符串字面值,在字符串引号前加
f
或F
,然后使用{变量或者表达式}
这个真第一次用
>>> f'1+1 = {1+1}'
'1+1 = 2'
- 字符串
str.format()
方法需要更多手动操作,通用使用{}
来标记将被替换的位置,还有详细的格式化指令,可以参考跟着官网学python(4):一探字符串
>>> yes_votes = 42_572_654
>>> no_votes = 43_132_495
>>> percentage = yes_votes / (yes_votes + no_votes)
>>> '{:-9} YES votes {:2.2%}'.format(yes_votes, percentage)
' 42572654 YES votes 49.67%'
原来数字赋值还可以用下划线分割,增加可读性。
- 最后,可以使用字符串切片和连接操作完成所有的字符串处理,创建可以想象的任何布局。比如符号标签、图形文字等等。字符串类型有一些方法可以将字符串填充到给定列宽的有用操作。
如果你不需要这些花哨的输出,只是想快速显示某些变量进行调式时,可以使用repr()
和str()
将任何函数转为字符串,第一个没用过。
str()
函数返回返回人类可读的值,repr()
是用于生成程序可读的值(可能会出现语法错误SyntaxError
),如果没有人类可读性表示的对象,他们返回一样的值。
>>> s = 'Hello, world.'
>>> str(s)
'Hello, world.'
>>> repr(s)
"'Hello, world.'" #注意看,单引号还在
顺便问一句,什么是没有人类可读性对象?
还记得string
模块吗,他有一个Template
类,人如其名,模板类,也可以将值替换为字符串,使用占位符$x
,用字典中的值替换他们,但是对格式控制不多。
格式化字符串文字
格式化字符串字面值(简称f-字符串),能让你在字符串前加上 f
和 F
并将表达式写成 {expression}
来在字符串中包含 Python 表达式的值。
说是3.6才新增的功能,更新详细可以查阅Python语言参考。
可选的格式说明符可以跟在表达式后面。这样可以更好地控制值的格式化方式。以下示例将pi舍入到小数点后三位:
>>> import math
>>> print(f'The value of pi is approximately {math.pi:.3f}.')
The value of pi is approximately 3.142.
可以在:
后跟一个整数实现快速对齐
>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678}
>>> for name, phone in table.items():
... print(f'{name:10} ==> {phone:10d}')
...
Sjoerd ==> 4127
Jack ==> 4098
Dcab ==> 7678
还支持其他修饰符,可以在格式化前转换值,如'!a'
应用 ascii()
,'!s'
应用 str()
,还有 '!r'
应用 repr()
:
再看下示例
>>> animals = 'eels'
>>> print(f'My hovercraft is full of {animals}.')
My hovercraft is full of eels.
>>> print(f'My hovercraft is full of {animals!r}.')
My hovercraft is full of 'eels'.
注意到!r
对应repr()
,正如前面所说,保留了字符串的单引号。
字符串的format()方法
再次看一下str.format()
方法的基本用法:
>>> print('I like {}!'.format('Python'))
I like Python!
花括号和其中的字符(称为格式字段)将替换为传递给 str.format()
方法的对象。
花括号中的数字可用来表示传递给 str.format()
方法的对象的位置,还可以使用关键字参数(**变量可以作为关键字参数传递),以及两者的组合。
>>> print('The story of {0}, {1}, and {other}.'.format('Bill', 'Manfred',other='Georg'))
The story of Bill, Manfred, and Georg.
比如下面几行代码生成一组整齐的列,其中包含给定的整数和它的平方以及立方:
>>> for x in range(1, 6):
... print('{0:2d} {1:3d} {2:4d}'.format(x, x*x, x*x*x))
...1 1 12 4 83 9 274 16 645 25 125
手动格式化字符串
同样平方和立方的表,手动格式化需要自己控制格式:
>>> 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 12 4 83 9 274 16 645 25 125
字符串对象的str.rjust()
方法通过在左侧填充空格来对给定宽度的字段中的字符串进行右对齐。类似str.ljust()
和 str.center()
,如果字符串太长,不会被截断,如果想截断需要人为切片。
旧的字符串格式化方法%
%
运算符也可用于字符串格式化
>>> import math
>>> print('The value of pi is approximately %.3f.' % math.pi)
The value of pi is approximately 3.142.
读写文件
前面这么久,我们都没涉及文件的读写,其实文件读写又是一门语言的必备要素。
python内置函数open()
返回一个file object,最常用的两个参数open(filename,mode)
,如
>>> f = open('workfile', 'w')
第一个参数filename
是包含文件名的字符串,可以是相对路径或绝对路径;
第二个参数mode
是指打开文件的方式,可选参数,默认为r
,参数含义如下:
'r'
表示文件只能读取'w'
表示只能写入(已存在的同名文件会被删除)'a'
表示打开文件以追加内容;任何写入的数据会自动添加到文件的末尾。'r+'
表示打开文件进行读写't'
默认值,以 text mode(文本方式)打开,以指定的编码方式进行编码或平台默认的编码,返回str
对象'b'
以 binary mode(二进制模式) 打开文件,不进行任何解码,返回bytes
对象
注意在文本模式下读写\n
会转换为平台换行符,直接修改可能会破坏二进制格式的数据,要小心。
文件处理完毕后,应该调用f.close()
关闭文件并立即释放它使用的所有系统资源。虽然就算你忘记关闭,Python的垃圾回收器最终将销毁该对象并为你关闭打开的文件,但是这就不知道什么时候的事了,总之不好。
更简单是使用with
关键字,后面子句执行完毕会自动关闭:
>>> with open('workfile') as f:
... read_data = f.read()
>>> f.closed
True
通过 with
语句或者调用 f.close()
关闭文件对象后,尝试使用该文件对象将自动失败。
文件对象file object的方法
f.read(size)
可以读取文件内容,在文本模式下返回size
个字符,在二进制模式下返回size
个字节。
size
可选,为空或负数时返回整个文件内容,如果已到达文件末尾,f.read()
将返回一个空字符串''
。
>>> f.read()
'This is the entire file.\n'
>>> f.read()
''
比如第一个read()
已经读取全部内容了,第二个read()
已经到尾部,只能返回''
。
f.readline()
从文件中读取一行,换行符\n
留在字符串的末尾,注意如果最后一行没有\n
,则无法读取。
还可以直接用in
关键字变量文件对象f
,这是内存高效,快速的,并简化的代码
>>> for line in f:
... print(line, end='')
...
This is the first line of the file.
Second line of the file
如果想以列表形式读取文件中的所有行,可以使用 list(f)
或 f.readlines()
。
f.write(string)
会把 string
的内容写入到文件中,并返回写入的字符数。
>>> f.write('This is a test\n')
15
在写入其他对象时,需要先转换为字符串str
(文本模式)或字节对象bytes
(二进制模式)。
同样的f.writelines()
可以接受列表形式参数,一次性写入多行。
f.tell()
返回一个整数,给出文件对象在文件中的当前位置,二进制模式下从文件开始的字节数,文本模式下意义不明的数字。
f.seek(offset, whence)
可以改变文件对象的位置,通过向一个参考点(whence
)添加offset
来计算文件对象位置,其中whence
的 0 值表示从文件开头起算,1 表示使用当前文件位置,2表示使用文件末尾作为参考点,可选参数,默认为0。
>>> f = open('workfile', 'rb+')
>>> f.write(b'0123456789abcdef')
16
>>> f.seek(5) #去到文件的第6个字节
5
>>> f.read(1) #读取一个字节内容,果然为b'5'
b'5'
>>> f.seek(-3, 2) #去到倒数第3个字节
13
>>> f.read(1)
b'd'
在文本模式下,只允许相对于文件开头搜索(使用 seek(0, 2)
搜索到文件末尾是个例外)并且唯一有效的 offset
值是那些能从 f.tell()
中返回的或者是零。其他 offset 值都会产生未定义的行为。
文件对象还要一些不常用的方法,如isatty()
和 truncate()
等,可以查询Python库参考。
使用JSON保存结构化数据
字符串可以很轻松地写入文件并从文件中读取出来。
数字可能会费点劲,因为 read()
方法只能返回字符串,然后用int()
函数处理。
当你想保存诸如嵌套列表和字典这样更复杂的数据类型时,手动解析和序列化会变得复杂。
Python可以使用JSON而不是让用户不断的编写和调试代码以将复杂的数据类型保存到文件中。
有一个标准模块json
实现Python数据结构到字符串的转换,称为序列化(serializing)。同样从字符串中重建数据称为反序列化(deserializing)。
在序列化和反序列化之间,表示对象的字符串可能已存储在文件或数据中,或通过网络连接发送到某个远程机器。
>>> import json
>>> json.dumps([1, 'simple', 'list'])
'[1, "simple", "list"]'
json.dumps
和json.loads
实现对Python数据结构的编码和解码,就是与字符串之间的变换。
还有变体组合dump()
和load()
,更多需要参考标准库。
Python还有一个特有的pickle
封存模块,允许对任意复杂 Python 对象进行序列化的协议,但是是不安全的,如果数据是由熟练的攻击者精心设计的,则反序列化来自不受信任来源的 pickle 数据可以执行任意代码。也就是CTF中渗透攻击,其实反序列化是CTF中一个常见题型,只是我不会。
内容好像不够多,继续学习第8章错误和异常。
虽然一直跟着官网走,但是相信你的代码也遇到一些Python的语法错误或异常。
语法错误
语法错误又称解析错误,可能是你在学习Python 时最容易遇到的错误:
>>> while True print('Hello world')File "<stdin>", line 1while True print('Hello world')^
SyntaxError: invalid syntax
只要遇到SyntaxError: invalid syntax,那么就是代码写错了,检查中英文,冒号、缩进、括号闭合等。
会显示出现语法错误文件名和行号,并显示一个“箭头”,请检查前后行,很多时候是前面没有冒号或者括号没有正常闭合等。
异常
即使语句或表达式在语法上是正确的,但在尝试执行时,它仍可能会引发错误。
在执行时检测到的错误被称为异常,异常不一定会导致严重后果,比如除零异常:
>>> 10 * (1/0)
Traceback (most recent call last):File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
错误信息显示异常类型和详细信息,比如NameError: name 'spam' is not defined
,变量spam
没有定义,同时错误信息还以堆栈回溯的形式显示发生异常时的上下文调用关系,非常直观。
除了系统内置异常,用户可以自定义异常类型。
异常处理
写一个简单的代码,实现如下功能:
要求用户一直输入,直到输入的是一个有效的整数。
>>> while True:
... try:
... x = int(input("Please enter a number: "))
... break
... except ValueError:
... print("Oops! That was no valid number. Try again...")
try except
语句可以用来处理异常,当你认为某段代码可能发生异常时,可以用try except
包围它,并在except
子句实现异常逻辑。
try
语句的工作原理如下:
首先,执行
try
子句(try
和except
关键字之间的(多行)语句,需要缩进)。如果没有异常发生,则跳过
except
子句 并完成try
语句的执行。如果在执行
try
子句时发生了异常,则跳过该子句中剩下的部分。然后,如果异常的类型和 except 关键字后面的异常匹配,则执行except
子句,然后继续执行后续语句,代码不会中断。如果发生的异常和
except
子句中指定的异常不匹配,则将其传递到外部的try
语句中;如果没有找到处理程序,则它是一个未处理异常,执行将停止并显示如上所示的消息。
所以很多时候我不except
具体异常,所以异常都处理。但是官网不建议这样做,很容易掩盖真正的编程错误!
原生的try
语句支持多个except
子句以指定不同异常的处理程序,最多会执行一个处理程序,类似只执行一次if elif
。同时一个except
子句可以将多个异常命名为带括号的元组,如:
... except (RuntimeError, TypeError, NameError):
... pass
如果发生的异常和 except
子句中的类是同一个类或者是它的基类,则异常和 except
子句中的类是兼容的,但反过来则不成立。
try ... except
语句有一个可选的 else
子句,在使用时必须放在所有的 except
子句后面。
对于在try
子句不引发异常时必须执行的代码来说很有用
for arg in sys.argv[1:]:try:f = open(arg, 'r')except OSError:print('cannot open', arg)else:print(arg, 'has', len(f.readlines()), 'lines')f.close()
else
子句避免了意外捕获由try ... except
语句保护的代码未引发的异常,比如上面的f.close()
,因为你不确定前面的文件是否被打开,只有放在else
语句。
发生异常时,它可能具有关联值,也称为异常参数 。参数的存在和类型取决于异常类型。
except
子句可以在异常名称后面指定一个变量。这个变量和一个异常实例绑定,它的参数存储在 instance.args
中。
为了方便起见,异常实例定义了 __str__()
,因此可以直接打印参数而无需引用 .args
。
也可以在抛出之前首先实例化异常,并根据需要向其添加任何属性。
>>> try:
... raise Exception('spam', 'eggs')
... except Exception as inst:
... print(type(inst)) #异常实例
... print(inst.args) #.args返回参数类别
... print(inst) # __str__ 可以直接打印
... x, y = inst.args # 参数解包
... print('x =', x)
... print('y =', y)
...
<class 'Exception'>
('spam', 'eggs')
('spam', 'eggs')
x = spam
y = eggs
如果异常有参数,则它们将作为未处理异常的消息的最后一部分('详细信息')打印。
同时异常处理程序不仅处理 try
子句中遇到的异常,还处理 try
子句中调用(即使是间接地)的函数内部发生的异常。
抛出异常
raise 语句允许程序员强制发生指定的异常,如
>>> raise NameError('HiThere')
Traceback (most recent call last):File "<stdin>", line 1, in <module>
NameError: HiThere
raise
唯一的参数就是要抛出的异常。
这个参数必须是一个异常实例或者是一个异常类(派生自Exception
的类)。
如果传递的是一个异常类,它将通过调用没有参数的构造函数来隐式实例化.
如果你需要确定是否引发了异常但不打算处理它,则可以使用更简单的 raise
语句形式重新引发异常
>>> try:
... raise NameError('HiThere')
... except NameError:
... print('An exception flew by!')
... raise
...
An exception flew by!
Traceback (most recent call last):File "<stdin>", line 2, in <module>
NameError: HiThere
用户自定义的异常
程序可以通过创建新的异常类来命名它们自己的异常(有关Python 类的知识,我们下周分享)。
异常通常应该直接或间接地从Exception
类派生。
class Error(Exception):passclass InputError(Error):def __init__(self, expression, message):self.expression = expressionself.message = message
大多数异常都定义为名称以“Error”结尾,类似于标准异常的命名。
定义清理操作
try
语句有另一个可选子句,用于定义必须在所有情况下执行的清理操作,如:
>>> try:
... raise KeyboardInterrupt
... finally:
... print('Goodbye, world!')
...
Goodbye, world!
KeyboardInterrupt
Traceback (most recent call last):File "<stdin>", line 2, in <module>
finally
子句将作为 try
语句结束前的最后一项任务被执行。 finally
子句不论 try
语句是否产生了异常都会被执行。
如果在执行
try
子句期间发生了异常,该异常可由一个except
子句进行处理。 如果异常没有被某个except
子句所处理,则该异常会在finally
子句执行之后被重新引发。异常也可能在
except
或else
子句执行期间发生。该异常会在finally
子句执行之后被重新引发。如果在执行
try
语句时遇到一个break
,continue
或return
语句,则finally
子句将在执行break
,continue
或return
语句之前被执行。如果
finally
子句中包含一个return
语句,则返回值将来自finally
子句的某个return
语句的返回值,而非来自try
子句的return
语句的返回值。如:
>>> def bool_return():
... try:
... return True
... finally:
... return False
...
>>> bool_return()
False
官网提供了一个更复杂的例子如下:
>>> def divide(x, y):
... try:
... result = x / y
... except ZeroDivisionError:
... print("division by zero!")
... else:
... print("result is", result)
... finally:
... print("executing finally clause")
...
>>> divide(2, 1)
result is 2.0
executing finally clause
>>> divide(2, 0)
division by zero!
executing finally clause
>>> divide("2", "1")
executing finally clause
Traceback (most recent call last):File "<stdin>", line 1, in <module>File "<stdin>", line 3, in divide
TypeError: unsupported operand type(s) for /: 'str' and 'str'
可以发现finally
子句在任何情况下都会被执行。 两个字符串相除所引发的 TypeError
不会由 except
子句处理,因此会在 finally
子句执行后被重新引发。
在实际应用程序中,finally
子句对于释放外部资源(例如文件或者网络连接)非常有用,无论是否成功使用资源。
预定义的清理操作
某些对象定义了在不再需要该对象时要执行的标准清理操作,无论使用该对象的操作是成功还是失败。比如前面我们学过文件读入,
for line in open("myfile.txt"):print(line, end="")
代码执行后会使文件在一段不确定的时间内处于打开状态,对于较大的应用程序来说可能是个问题。
正如前面所使用的,with
语句允许像文件这样的对象能够以一种确保它们得到及时和正确的清理的方式使用。
with open("myfile.txt") as f:for line in f:print(line, end="")
执行完语句后,即使在处理行时遇到问题,文件f
也始终会被关闭。
和文件一样,提供预定义清理操作的对象将在其文档中指出这一点,请学会使用。
03 为什么
为什么要这么做?
首先任何东西的官方文档都是最全面最权威的教程。
以前只是受限于英语水平,
对官方网站敬而远之,
遇到问题都百度,
很多答案讲的都不到位,
没有说明为什么?
越到后面,收获越大。
输入输出用的比较多,文件读写也是,以前不喜欢用wiht
,以后要改。
第一次知道f-字符串用法,很方便,第一次接触repr()
函数,需要了解。
对读写文件的理解更加深刻,学会了一些以前没用过的方法,如seek()
等。
又比如虽然经常try except
,但是从未深究,也没用过else
字句和finally
子句。
收获满满。
04 更好的选择
有没有更好的选择
还是那句话,多敲代码,结合案例,偶然看看官方源代码,加深理解。
比如我们维护大型项目是需要用到配置文件,如何以json形式保存、读取配置文件呢?看一个简单的示例:
import json
with open("setting.json", "r", encoding="utf-8") as file:settings = json.load(file)然后可以进行处理,也可以封装为函数。
一句话
格式化输出想要的信息,str()
、repr
、str.format()
、f-string
灵活运用;读写文件先打开再关闭,with
语句很好用,open()
模式要分清,文本模式与二进制模式,是否可写,read()
、write()
要会用。
代码语法错误要避免,异常要处理,try ... except ... else ... finally
语句要会用。
跟着官网学Python(8):输入输出相关推荐
- 跟着官网学k8s-05运行应用程序的多个实例
一般情况下pod的数量不会是一个,多个pod可以让服务更加的可靠并且可以承受更大的流量. service的type类型可以为LoadBalancer即负载均衡.使用该类型service需要指定外部负载 ...
- 跟着官网学k8s-04使用Service暴露您的应用
本节主要介绍sk8s中的service Kubernetes 的 Service 是一个抽象层,它定义了一组 Pod 的逻辑集,并为这些 Pod 支持外部流量暴露.负载平衡和服务发现 简单说,serv ...
- python菜鸟教程官网pandas,python菜鸟教程官网numpy
求比较好的Python练习网站 适合 Python 入门学习的5个网站1. Python官方网站最权威的 Python 教程.2. 菜鸟教程 Python 教程基本入门级教程,还有一些简单的进阶教程. ...
- 黑帽python_seo黑白帽:关键词排名官网,Python 黑帽SEO
由所以以seo为起点,不是以职业和用户为起点,所以此类网站往往会是一群不理解这个职业的人在运营. 为每一页和每一篇文章编撰质量描述和呼吁采纳举动,为搜索者拜访您的网站供给理由,并进步从搜索引擎成果页到 ...
- 怎么在python官网下载python,官网python怎么下载安装
python怎么安装 在Python官网下载Python安装包,双击打开Python软件.勾选add Python 3.8 to PATH,点击install Now. 安装完成后,点击Close.打 ...
- bigsur cdr文件_从苹果BigSur官网学点东西
从苹果BigSur官网学点东西 Awsome配色 这个 蓝紫渐变大底 + 简洁的 矩形状字块 + 粗细层次字形,看着就蛮舒服. 看看css配色: .section-hero div[data-comp ...
- python官网地址-python官方网站
广告关闭 2017年12月,云+社区对外发布,从最开始的技术博客到现在拥有多个社区产品.未来,我们一起乘风破浪,创造无限可能. 由于整个python语言从规范到解释器都是开源的,所以理论上,只要水平够 ...
- python官网地址-python官网地址
广告关闭 2017年12月,云+社区对外发布,从最开始的技术博客到现在拥有多个社区产品.未来,我们一起乘风破浪,创造无限可能. 如果您的项目环境尚未安装 pip,请参见 pip官网 进行安装. pip ...
- python官网地址-python官网网址
广告关闭 腾讯云双11爆品提前享,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高满返5000元! 通过 pip 安装(推荐)您可以通过执行以下命令,将腾讯云 api python ...
最新文章
- 滇西应用技术大学计算机专业在哪里,滇西应用技术大学
- 201771010102 常惠琢 《2018面向对象程序设计(Java)》第9周学习总结
- [设计模式]开闭原则
- 【NC14 按之字形顺序打印二叉树】
- Numpy之Broadcasting
- WAF(NGINX)中502和504的区别
- 无法回应的ARP请求包导致的网站缓慢问题排错
- URL Loading System官方文档翻译一
- 基于持续集成的轻量级接口自动化测试 【持续更新...】
- POJ 3683 Priest John's Busiest Day
- 拓端tecdat|R语言生存分析: 时变竞争风险模型分析淋巴瘤患者
- C#中ListView分页操作
- 分形之——谢尔宾斯基三角形
- oracle现金流量表逻辑,【实战】编制现金流量表的一些个人理解(附下载勾稽表)...
- linux中dns服务故障,Linux DNS服务器故障解决
- 统计试验设计的常用模型
- macOS--苹果本安装Win(看完可省200块)
- 论坛上关于几个国家别称的由来
- WPF+WCF一步一步打造音频聊天室(二):文字聊天和白板共享
- 计算机编程课程顺序_470道免费的在线编程和计算机科学课程,四月开始