'''
作者:韭白
源自:
https://www.cnblogs.com/shockerli/p/python-study-note.html
'''
错误和异常
语法错误
SyntaxError 类表示语法错误,当解释器发现代码无法通过语法检查时会触发的错误。语法错误是无法用
try...except...
捕获的。
>>> print:
File "", line 1
print:
^
SyntaxError: invalid syntax
异常
即便程序的语法是正确的,在运行它的时候,也有可能发生错误。运行时发生的错误被称为异常。
错误信息的前面部分显示了异常发生的上下文,并以调用栈的形式显示具体信息。
>>> 1 + '0'
Traceback (most recent call last):
File "", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'
异常处理
Python 提供了
try ... except ...
的语法结构来捕获和处理异常。
try 语句执行流程大致如下:
st=>start: try 子句
cond_has_error=>condition: 是否有异常
cond_has_else=>condition: 是否有 else 子句
cond_has_finally=>condition: 是否有 finally 子句
io=>inputoutput: verification
op_except=>operation: except 子句处理异常
op_else=>operation: 执行 else 子句
op_finally=>operation: 执行 finally 子句
e=>end: 结束
st->cond_has_error
cond_has_error(yes, right)->op_except->cond_has_else
cond_has_error(no)->cond_has_else
cond_has_else(yes, right)->op_else->cond_has_finally
cond_has_else(no)->cond_has_finally
cond_has_finally(yes, right)->op_finally->e
cond_has_finally(no)->e
-
首先,执行 try 子句(在关键字 try 和关键字 except 之间的语句)
-
如果没有异常发生,忽略 except 子句,try 子句执行后结束。
-
如果在执行 try 子句的过程中发生了异常,那么 try 子句余下的部分将被忽略。如果异常的类型和 except 之后的名称相符,那么对应的 except 子句将被执行。最后执行 try 语句之后的代码。
-
如果一个异常没有与任何的 except 匹配,那么这个异常将会传递给上层的 try 中。
-
一个 try 语句可能包含多个 except 子句,分别来处理不同的特定的异常。
-
最多只有一个 except 子句会被执行。
-
处理程序将只针对对应的 try 子句中的异常进行处理,而不是其他的 try 的处理程序中的异常。
-
一个 except 子句可以同时处理多个异常,这些异常将被放在一个括号里成为一个元组。
-
最后一个 except 子句可以忽略异常的名称,它将被当作通配符使用。可以使用这种方法打印一个错误信息,然后再次把异常抛出。
-
try except 语句还有一个可选的 else 子句,如果使用这个子句,那么必须放在所有的 except 子句之后。这个子句将在 try 子句没有发生任何异常的时候执行。
-
异常处理并不仅仅处理那些直接发生在 try 子句中的异常,而且还能处理子句中调用的函数(甚至间接调用的函数)里抛出的异常。
-
不管 try 子句里面有没有发生异常,finally 子句都会执行。
-
如果一个异常在 try 子句里(或者在 except 和 else 子句里)被抛出,而又没有任何的 except 把它截住,那么这个异常会在 finally 子句执行后再次被抛出。
抛出异常
使用
raise
语句抛出一个指定的异常。
raise 唯一的一个参数指定了要被抛出的异常。它必须是一个异常的实例或者是异常的类(也就是 Exception 的子类)。
如果你只想知道这是否抛出了一个异常,并不想去处理它,那么一个简单的 raise 语句就可以再次把它抛出。
自定义异常
可以通过创建一个新的异常类来拥有自己的异常。异常类继承自 Exception 类,可以直接继承,或者间接继承。
当创建一个模块有可能抛出多种不同的异常时,一种通常的做法是为这个包建立一个基础异常类,然后基于这个基础类为不同的错误情况创建不同的子类。
大多数的异常的名字都以"Error"结尾,就跟标准的异常命名一样。
实例
import sys
class Error(Exception):
"""Base class for exceptions in this module."""
pass
class InputError(Error):
"""Exception raised for errors in the input.
Attributes:
expression -- input expression in which the error occurred
message -- explanation of the error
"""
def __init__(self, expression, message):
self.expression = expression
self.message = message
try:
print('code start running...')
raise InputError('input()', 'input error')
int('a')
s = 1 + 'a'
dit = {'name': 'john'}
print(dit['1'])
except InputError as ex:
print("InputError:", ex.message)
except TypeError as ex:
print('TypeError:'
, ex.args)
pass
except (KeyError, IndexError) as ex:
"""支持同时处理多个异常, 用括号放到元组里"""
print(sys.exc_info())
except:
"""捕获其他未指定的异常"""
print("Unexpected error:", sys.exc_info()[0])
raise RuntimeError('RuntimeError')
else:
"""当无任何异常时, 会执行 else 子句"""
print('"else" 子句...')
finally:
"""无论有无异常, 均会执行 finally"""
print('finally, ending')
文件操作
打开文件
open()
函数用于打开/创建一个文件,并返回一个 file 对象:
open(filename, mode)
文件打开模式:
r
|
以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。
|
rb
|
以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。
|
r+
|
打开一个文件用于读写。文件指针将会放在文件的开头。
|
rb+
|
以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。
|
w
|
打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
|
wb
|
以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
|
w+
|
打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
|
wb+
|
以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
|
a
|
打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
|
ab
|
以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
|
a+
|
打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。
|
ab+
|
以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。
|
文件对象方法
-
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。
-
next(iterator[,default])
Python 3 中的 File 对象不支持 next() 方法。 Python 3 的内置函数
next()
通过迭代器调用
__next__()
方法返回下一项。在循环中,
next()
函数会在每次循环中调用,该方法返回文件的下一行,如果到达结尾(EOF),则触发 StopIteration。
-
fileObject.read()
read() 方法用于从文件读取指定的字节数,如果未给定或为负则读取所有。
-
fileObject.readline()
readline() 方法用于从文件读取整行,包括 "\n" 字符。如果指定了一个非负数的参数,则返回指定大小的字节数,包括 "\n" 字符。
-
fileObject.readlines()
readlines() 方法用于读取所有行(直到结束符 EOF)并返回列表,该列表可以由 Python 的
for... in ...
结构进行处理。如果碰到结束符 EOF,则返回空字符串。
-
fileObject.seek(offset[, whence])
seek() 方法用于移动文件读取指针到指定位置。
whence 的值, 如果是 0 表示开头, 如果是 1 表示当前位置, 2 表示文件的结尾。whence 值为默认为0,即文件开头。例如:
seek(x, 0)
:从起始位置即文件首行首字符开始移动 x 个字符
seek(x, 1)
:表示从当前位置往后移动 x 个字符
seek(-x, 2)
:表示从文件的结尾往前移动 x 个字符
-
fileObject.tell(offset[, whence])
tell() 方法返回文件的当前位置,即文件指针当前位置。
-
fileObject.truncate([size])
truncate() 方法用于从文件的首行首字符开始截断,截断文件为 size 个字符,无 size 表示从当前位置截断;截断之后 V 后面的所有字符被删除,其中 Widnows 系统下的换行代表2个字符大小。
-
fileObject.write([str])
write() 方法用于向文件中写入指定字符串。
在文件关闭前或缓冲区刷新前,字符串内容存储在缓冲区中,这时你在文件中是看不到写入的内容的。
如果文件打开模式带 b,那写入文件内容时,str (参数)要用 encode 方法转为 bytes 形式,否则报错:
TypeError: a bytes-like object is required, not 'str'
。
-
fileObject.writelines([str])
writelines() 方法用于向文件中写入一序列的字符串。这一序列字符串可以是由迭代对象产生的,如一个字符串列表。换行需要指定换行符
\n
。
实例
filename = 'data.log'
with open(filename, 'w+', encoding='utf-8') as file:
print('文件名称: {}'.format(file.name))
print('文件编码: {}'.format(file.encoding))
print('文件打开模式: {}'.format(file.mode))
print('文件是否可读: {}'.format(file.readable()))
print('文件是否可写: {}'.format(file.writable()))
print('此时文件指针位置为: {}'.format(file.tell()))
num = file.write("第一行内容\n")
print('写入文件 {} 个字符'.format(num))
print(file.readline(), file.tell())
file.seek(0)
print(file.readline(), file.tell())
file.write('第二次写入的内容\n')
print(file.readline(), file.tell())
file.seek(0)
print(file.read(9))
file.seek(0)
print(file.readlines())
file.seek(0)
for line in file:
print(line, end='')
if not file.closed:
file.close()
输出:
文件名称: data.log
文件编码: utf-8
文件打开模式: w+
文件是否可读: True
文件是否可写: True
此时文件指针位置为: 0
写入文件 6 个字符
16
第一行内容
16
41
第一行内容
第二次
['第一行内容\n', '第二次写入的内容\n']
第一行内容
第二次写入的内容
序列化
在 Python 中 pickle 模块实现对数据的序列化和反序列化。pickle 支持任何数据类型,包括内置数据类型、函数、类、对象等。
方法
dump
将数据对象序列化后写入文件
pickle.dump(obj, file, protocol=None, fix_imports=True)
必填参数 obj 表示将要封装的对象。
必填参数 file 表示 obj 要写入的文件对象,file 必须以二进制可写模式打开,即
wb
。
可选参数 protocol 表示告知 pickle 使用的协议,支持的协议有 0,1,2,3,默认的协议是添加在 Python 3 中的协议3。
load
从文件中读取内容并反序列化
pickle.load(file, fix_imports=True, encoding='ASCII'