异常处理

异常:程序正常执行过程中出现的不正常的情况,该情况影响了程序的正常执行。

异常程序:是指程序执行的非法指令,比如常见的非法操作码,地址越界,算术溢出等,异常程序的出现一般有两种情况:

Python提供了两个非常重要的功能来处理程序在运行中出现的异常和错误。经常使用的是try…except语句,拓展一下就是try-except-else-finally,另一个是断言.

各个语句的功能:

  • try:正常执行的程序,如果执行过程中出现异常,则中断当前的程序执行,跳转到对应的异常处理模块中;

  • except可选 ,如果异常与A/B相匹配,则跳转到对应的except A/B中执行;如果A、B中没有相对应的异常,则跳转到except中执行。(这个except块是可选的,如果没有提供,则执行python默认的异常处理程序,即:中断执行,打印提示信息)

    为异常类型,可指定可不指定

  • else可选,如果try中的程序执行过程中没有发生错误且无返回值,则会继续执行else中的程序;

  • finally可选,无论是否发生异常,只要提供了finally程序,就在执行所有步骤之后执行finally中的程序。

    正常执行的程序在try下面执行,在执行中如果发生了异常,则中断当前执行然后执行except中的部分,如果没有异常即不执行except的情况下,则会执行else中的语句,finally语句是最后无论是否有异常都要执行的代码。

顺序和执行规则

    1. 完整的格式顺序是:try —> except X —> except —> else—> finally
    2. 如果 elsefinally都存在的话,else必须在finally 之前,finally必须在整个程序的最后。
    3. else的存在是以exceptexcept X 的存在为前提,如果没有 except,而在try中使用else 的话,会出现语法错误。
    4. 如果程序没有错误,且try无返回值,会跳过exceptexcept X,执行else
  • 执行顺序和返回值分析

    首先,finally的优先级最高,如果有finally语句,那么它的语句一定会被执行(不管前面的语句有无返回值),如果finally有返回值,那么finally的返回值就是最终的返回值。

    其次,如果没有finally语句,要观察有没有返回值。

    如果是按照A—>B—>C的顺序执行,那么依次观察A、B、C的内部有无返回值,如果遇到了返回值,那么立即中断执行,后续语句不会执行。例如:

    • 无错误的情况下,语句按照try—>else的顺序,但是如果try有返回值,那么程序立即返回到了try的返回值,else语句不会被执行,最终的返回值也是try的返回值。

    • 同理,有错误的情况下,语句直接执行except,此时返回值就是except的返回值。如果是按照A—>B—>C的顺序执行,那么依次观察A、B、C的内部有无返回值,如果遇到了返回值,那么立即中断执行,后续语句不会执行。

    如果有finally语句,前面语句的执行顺序不变,执行完之后执行finally语句,如果finally有返回值,那么finally的返回值就是最终的返回值。如果finally无返回值,那么finally前面语句的返回值就是最终的返回值。

    例程1(无返回值)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    print("\n",'【无返回值】的时候'.center(60,'-'))
    print("【无finally】的时候".center(40,'-'))
    def fun(x):
    try:
    a=3/x
    print("try被执行——>",end='')

    except:
    print("expect被执行——>",end='')

    else:
    print("else被执行——>",end='')

    # finally:
    # return 'finally的返回值'

    # 没有错误的时候
    print("【无错误】的时候".center(20,'-'))
    fun(1)


    # 有错误的时候
    print("\n","【有错误】的时候".center(20,'-'))
    fun(0)


    print("\n","【有】finally的时候".center(40,'-'))
    def fun(x):
    try:
    a=3/x
    print("try被执行——>",end='')
    except:
    print("expect被执行——>",end='')
    else:
    print("else被执行——>",end='')
    finally:
    print('finally被执行',end='')

    # 没有错误的时候
    print("【无错误】的时候".center(20,'-'))
    fun(1)

    # 有错误的时候
    print("\n","【有错误】的时候".center(20,'-'))
    fun(0)

    例程2(有返回值)

    1
      

断言

断言语句用于判断某个表达式的值,如果值为真,则程序可以继续往下执行;反之,Python 解释器会报 AssertionError 错误。

一个复杂的程序,如果存在潜在的错误,与其让程序在晚些时候崩溃,不如在错误条件出现时,就直接让程序崩溃,这有利于我们对程序排错,提高程序的健壮性。

  • 语法:

    1
    2
    if not expression:
    raise AssertionError

    等价于

    1
    2
    3
    4
    if 表达式==True:
    程序继续执行
    else:
    程序报 AssertionError 错误
  • 例程

    1
    2
    3
    4
    5
    6
    # 从键盘读取时间
    hour=int(input("请输入现在的钟点:\n"))
    # 断言时间是0~24之间
    assert hour in range(0,25)
    # 如果时间是0~24之间,打印输出,否则抛出AssertionError错误
    print(f"现在是{hour}时")

    如果输入正确,会执行print(f”现在是{hour}时”)语句

    如果输入错误,比如输如25,会抛出错误:

1
2
3
4
Traceback (most recent call last):
File "E:\codes\Python\python_relearning\file&error.py", line 140, in <module>
assert hour in range(0,25)
AssertionError
  • 常见的断言函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    assertEqual(a, b)     a == b      
    assertNotEqual(a, b) a != b
    assertTrue(x) bool(x) is True
    assertFalse(x) bool(x) is False
    assertIs(a, b) a is b 2.7
    assertIsNot(a, b) a is not b 2.7
    assertIsNone(x) x is None 2.7
    assertIsNotNone(x) x is not None 2.7
    assertIn(a, b) a in b 2.7
    assertNotIn(a, b) a not in b 2.7
    assertIsInstance(a, b) isinstance(a, b) 2.7
    assertNotIsInstance(a, b) not isinstance(a, b) 2.7
  • 其他的断言函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    assertAlmostEqual(a, b)     round(a-b, 7) == 0      
    assertNotAlmostEqual(a, b) round(a-b, 7) != 0
    assertGreater(a, b) a > b 2.7
    assertGreaterEqual(a, b) a >= b 2.7
    assertLess(a, b) a < b 2.7
    assertLessEqual(a, b) a <= b 2.7
    assertRegexpMatches(s, re) regex.search(s) 2.7
    assertNotRegexpMatches(s, re) not regex.search(s) 2.7
    assertItemsEqual(a, b) sorted(a) == sorted(b) and works with unhashable objs 2.7
    assertDictContainsSubset(a, b) all the key/value pairs in a exist in b 2.7
    assertMultiLineEqual(a, b) strings 2.7
    assertSequenceEqual(a, b) sequences 2.7
    assertListEqual(a, b) lists 2.7
    assertTupleEqual(a, b) tuples 2.7
    assertSetEqual(a, b) sets or frozensets 2.7
    assertDictEqual(a, b) dicts 2.7
    assertMultiLineEqual(a, b) strings 2.7
    assertSequenceEqual(a, b) sequences 2.7
    assertListEqual(a, b) lists 2.7
    assertTupleEqual(a, b) tuples 2.7
    assertSetEqual(a, b) sets or frozensets 2.7assertDictEqual(a, b) dicts 2.7

文件操作

open 和with open

open是Python的一个内置函数,一般用于本地文件的读写操作。with open不是一个整体,是使用了with语句的open函数。with open可以说是open的优化用法或高级用法,相比open更加简洁、安全。open函数必须搭配.close()方法使用,先用open打开文件,然后进行读写操作,最后用.close()释放文件。with open则无需.close()语句,所以说简洁。

如果文件不存在,会自动在路径下创建一个文件

完整的语法格式

1
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)

参数说明:

  • file: 必需,文件路径(相对或者绝对路径)。

  • mode: 可选,文件打开模式

  • buffering: 设置缓冲

  • encoding: 一般使用utf8

  • errors: 报错级别

  • newline: 区分换行符

  • closefd: 传入的file参数类型

  • opener: 设置自定义开启器,开启器的返回值必须是一个打开的文件描述符。

  • 例程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 方式1
filepath1='file1.txt'
with open(filepath1,'w')as file:
for i in range(3):
file.write(f"这是第{i+1}行\n")
print("文件已写入!")

# 方式2
filepath2='file2.txt'
file=open(filepath2, 'w')
try:

for i in range(3):
file.write(f"这是第{i+1}行\n")
print("文件已写入!")

finally:
file.close()

参数mode的类型

模式 描述
t 文本模式 (默认)。
x 写模式,新建一个文件,如果该文件已存在则会报错。
b 二进制模式。
+ 打开一个文件进行更新(可读可写)。
U 通用换行模式(Python 3 不支持)。
r 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。
rb 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。一般用于非文本文件如图片等。
r+ 打开一个文件用于读写。文件指针将会放在文件的开头。
rb+ 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。一般用于非文本文件如图片等。
w 打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。
w+ 打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb+ 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。
a 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
ab 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
a+ 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。
ab+ 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。

file 对象的属性

属性 描述
file.closed 如果文件已被关闭,返回true,否则返回false
file.mode 返回被打开文件的访问模式
file.name 返回文件的名称

file对象的方法

序号 方法及描述
1 file.close()关闭文件。关闭后文件不能再进行读写操作。
2 file.flush() 刷新文件内部缓冲,直接把内部缓冲区的数据立刻写入文件, 而不是被动的等待文件关闭后自动刷新缓冲区。
3 file.fileno()返回一个整型的文件描述符(file descriptor FD 整型), 可以用在如os模块的read方法等一些底层操作上。
4 file.isatty()如果文件连接到一个终端设备返回 True,否则返回 False。
5 file.next()返回文件下一行。
6 file.read([size])读取整个文件,返回的是一个字符串,字符串包括文件中的所有内容从文件读取指定的字节数,如果未给定或为负则读取所有。默认为 -1,表示读取整个文件。返回的是一个字符串,字符串包括文件中的所有内容。速度最快
7 file.readline([size])每次读取下一行文件,包括 “\n” 字符。如果指定了一个非负数的参数,则返回指定大小的字节数,包括 “\n” 字符。当内存不足时,使用readline()可以每次读取一行数据,只需要很少的内存
8 file.readlines([sizeint])读取所有行并返回列表,若给定sizeint>0,则是设置一次读多少字节,这是为了减轻读取压力.
9 **file.seek(offset[, whence])设置文件当前位置,
offset: 将光标向前移动n个位置,n可以是负数
whence: 参考位置,一般参数为0,1,2

0 :将开头作为参考位置

1 :将当前作为参考位置

2 :将末尾作为参考位置**
10 file.tell()返回文件当前位置。即文件指针当前位置
11 file.truncate([size])截取文件,截取的字节通过size指定,默认为当前文件位置。返回截断的字节长度。参数size是从当前位置开始保留的字符长度,超过size的就截断丢弃,汉字GBK编码,一个汉字长度为2,字母是1
12 file.write(str)将字符串写入文件,返回的是写入的字符长度。
13 file.writelines(sequence)向文件写入一个序列(如字符串列表),如果需要换行则要自己加入每行的换行符。

常用的文件操作

打开文件,读取内容

1
2
3
4
# 打开文件并读取内容
with open('example.txt', 'r') as file:
content = file.read()
print(content)

写入内容

1
2
3
# 写入文件
with open('example.txt', 'w') as file:
file.write('Hello, World!')

追加内容到文件

1
2
3
4
# 追加内容到文件
with open('example.txt', 'a') as file:
file.write('
New line')

读取文件的某一行

1
2
3
4
# 读取文件的某一行
with open('example.txt', 'r') as file:
line = file.readlines()[0]
print(line)

逐行读取文件

1
2
3
4
# 逐行读取文件
with open('example.txt', 'r') as file:
for line in file:
print(line.strip())

使用fileinput模块修改文件内容

1
2
3
4
5
import fileinput

# 使用fileinput模块修改文件内容
for line in fileinput.input('example.txt', inplace=True):
print(line.replace('old_text', 'new_text'), end='')

复制文件

1
2
3
# 复制文件
with open('example.txt', 'r') as source, open('copy.txt', 'w') as destination:
destination.write(source.read())

移动文件

1
2
3
4
# 移动文件
import os

os.rename('example.txt', 'moved_example.txt')

删除文件

1
2
3
4
# 删除文件
import os

os.remove('example.txt')

重命名文件

1
2
3
4
# 重命名文件
import os

os.rename('example.txt', 'renamed_example.txt')

创建文件夹

1
2
3
4
# 创建文件夹
import os

os.mkdir('new_folder')

删除文件夹

1
2
3
4
# 删除文件夹
import os

os.rmdir('new_folder')

遍历文件夹下的所有文件

1
2
3
4
5
# 遍历文件夹中的所有文件
import os

for file in os.listdir('.'):
print(file)

获取文件大小

1
2
3
4
5
# 获取文件大小
import os

file_size = os.path.getsize('example.txt')
print(file_size)

检查文件是否存在

1
2
3
4
5
6
7
# 检查文件是否存在
import os

if os.path.exists('example.txt'):
print("文件存在")
else:
print("文件不存在")

读取文件并按行分割

1
2
3
4
# 读取文件并按行分割
with open('example.txt', 'r') as file:
lines = file.read().splitlines()
print(lines)

读取文件并统计行数

1
2
3
4
# 读取文件并统计行数
with open('example.txt', 'r') as file:
line_count = sum(1 for line in file)
print(line_count)

读取文件并查找特定文本

1
2
3
4
5
6
# 读取文件并查找特定文本
with open('example.txt', 'r') as file:
if 'target_text' in file.read():
print("找到目标文本")
else:
print("未找到目标文本")

将文件内容转换为列表

1
2
3
4
# 将文件内容转换为列表
with open('example.txt', 'r') as file:
content_list = file.read().split()
print(content_list)

将文件内容转换为字典

1
2
3
4
# 将文件内容转换为字典
with open('example.txt', 'r') as file:
content_dict = dict(line.split() for line in file)
print(content_dict)

写入多行内容到文件

1
2
3
4
5
# 写入多行内容到文件
with open('example.txt', 'w') as file:
file.write('Line 1
Line 2
Line 3')

使用pathlib模块复制文件

1
2
3
4
5
6
# 使用pathlib模块复制文件
from pathlib import Path

source = Path('example.txt')
destination = Path('copy.txt')
source.replace(destination)

使用pathlib模块创建和删除文件夹

1
2
3
4
5
6
7
8
9
# 使用pathlib模块创建和删除文件夹
from pathlib import Path

# 创建文件夹
new_folder = Path('new_folder')
new_folder.mkdir()

# 删除文件夹
new_folder.rmdir()

参考文章