Python-10:异常类型 & 正则表达式
1. 异常类型
1.1 类型分类
总的来说,编写程序时遇到的错误可大致分为 2 类,分别为语法错误和运行时错误。
1.1.1 语法错误
语法错误,即解析代码时出现的错误。当代码不符合 Python 语法规则时,Python 解释器在解析时就会报出 SyntaxError 语法错误,与此同时还会明确指出最早探测到错误的语句。
示例:
1 | print"Hello,World!" |
Python3 已不再支持上面这种写法,所以在运行时,解释器会报语法错误。
1.1.2 运行时错误
运行时错误,即程序在语法上都是正确的,但在运行时发生了错误。
示例:
1 | a=1/0 |
上面这句代码的意思是用 1 除以 0,并赋值给 a。因为 0 作除数是没有意义的,所以运行后会产生运行时错误。
1.2 常见异常类型
官网异常定义:https://docs.python.org/3/library/exceptions.html#base-dClasses
在 Python 中,把这种运行时产生错误的情况叫做异常(Exceptions),常见的几种异常情况如下。
| 异常类型 | 含义 | 实例 |
|---|---|---|
| AssertionError | 当 assert 关键字后的条件为假时,程序运行会停止并抛出 AssertionError 异常 | demo_list = [‘hello’]assert len(demo_list) < 0 |
| AttributeError | 当试图访问的对象属性不存在时抛出的异常 | age = 18age.len |
| IndexError | 索引超出序列范围会引发此异常 | demo_list = [‘hello’]demolist[3] |
| KeyError | 字典中查找一个不存在的关键字时引发此异常 | demo_dict = {‘url’: “www.baidu.com"}demo\_dict\["name"] |
| NameError | 尝试访问一个未声明的变量时,引发此异常 | |
| TypeError | 不同类型数据之间的无效操作 | 123 + “hello world” |
| ZeroDivisionError | 除法运算中除数为 0 引发此异常 | a = 1/0 |
1.3 异常处理
Python 异常相关的关键字主要有:
| 关键字 | 关键字说明 |
|---|---|
| try / except | 捕获异常并处理 |
| pass | 忽略异常 |
| as | 定义异常实例(exceptMyErrorase) |
| else | 如果 try 中的语句没有引发异常,则执行 else 中的语句 |
| finally | 无论是否出现异常,都执行的代码 |
| raise | 抛出 / 引发异常 |
1.3.1 Try - except
当发生异常时,我们就需要对异常进行捕获,然后进行相应的处理。python 的异常捕获常用 try…except… 结构,把可能发生错误的语句放在 try 模块里,用 except 来处理异常,每一个 try,都必须至少对应一个 except。
基本语法结构如下所示:
1 | try: |
举个简单的例子,下面两种写法是等价的,a / 0 在运行时会报异常,但是我用 try…except 捕捉后,就不会抛出异常而是执行 except 中的打印语句。
1 | # 写法一 |
如果我想同时捕获多种异常也是可以的,例如下面这个例子,针对不同异常情况进行相应的处理。
1 | try: |
1.3.2 Try - except - Else
在原本的 try except 结构的基础上,Python 异常处理机制还提供了一个 else 块,即 try except else 结构。
使用 else 包裹的代码,只有当 try 块没有捕获到任何异常时,才会得到执行;反之,如果 try 块捕获到异常,即调用对应的 except 来处理异常,else 块中的代码也不会得到执行。
1 | try: |
我们再来看一个完整点且复杂点的分析文本的例子,这里将使用方法 split( ) ,这里以空格为分隔符将字符串分拆成多个部分,并将这些部分都存储到一个列表中。
1 | title = "Alice in Wonderland" |
下面将分析多本书,并统计每本书有多少个单词。
1 | def count_words(filename): |
1.3.3 Try - except - Finally
Python 异常处理机制还提供了一个 finally 语句,通常用来为 try 快中的程序做扫尾清理工作。
在整个异常处理机制中,finally 语句的功能是:无论 try 块是否发生异常,最终都要进入 finally 语句,并执行其中的代码块。
1.3.4 Raise
当程序出现错误,Python 会自动引发异常,也可以通过 raise 显示地引发异常。一旦执行了 raise 语句,raise 后面的语句将不能执行。
raise 语句的基本语法格式为:
1 | raise [exceptionName [(reason)]] |
raise 语句有三种常用的用法:
- raise:单独一个 raise。该语句引发当前上下文中捕获的异常(比如在 except 块中),或默认引发 RuntimeError 异常。
- raise 异常类名称:raise 后带一个异常类名称,表示引发执行类型的异常。
- raise 异常类名称(描述信息):在引发指定类型的异常的同时,附带异常的描述信息。
对于一些未知的异常,我们就可以通过 raise 来触指定的异常,并通过 try except 相关捕获方法捕获该异常,这样就可以通过人工自定义的异常做相应的处理。
1 | def divide(a, b): |
1.4 获取异常信息
在实际调试程序的过程中,有时只获得异常的类型是远远不够的,还需要借助更详细的异常信息才能解决问题。
捕获异常时,有 2 种方式可获得更多的异常信息,分别是:
- 使用 sys 模块中的 exc_info 方法
- 使用 traceback 模块中的相关函数
使用 traceback 模块查看异常传播轨迹,首先需要将 traceback 模块引入,该模块提供了如下两个常用方法:
- traceback.print_exc():将异常传播轨迹信息输出到控制台或指定文件中。
- format_exc():返回一个字符串而不是打印到文件。
我们可以直接获取到错误的信息显示出来,并不会影响后续的执行。
1 | import traceback |
也可以将获取到的错误信息赋值给一个变量保存起来。
1 | import traceback |
2. 正则表达式
在线正则表达式测试:https://tool.oschina.net/regex/#
2.1 正则表达式详解
2.1.1 介绍
正则表达式是一种用于匹配和操作文本的规则或语法:
- 正则表达式拥有强大的文本处理能力,支持匹配、查找、替换等操作
- 广泛的应用领域,例如编程、数据处理、文本处理等领域
- 通用性强,跨语言跨场景
2.1.2 语法
| 匹配字符串结尾 | abc$ 表示 abc 在一个字符串的结尾 | | |
| () | 分组标记,内部只能使用\ | 操作符 | (abc) 表示 abc,(abc \ | def) 表示 abc、def |
| \d | 数字,等价于 [0-9] | | | |
| \w | 单词字符,等价于 [A-Za-z0-9_] | | | |
2.2 正则表达式实战
2.2.1 案例一
现在有这样一串字符,我需要根据需求查找出相应的字符信息。
1 | hello world 12345 is book 123 |
- 匹配出 hello 字符串
- 方法一:
hello - 方法二:
^hello
- 方法一:
- 匹配出所有数字
- 方法:
\d+
- 方法:
- 匹配出所有字符串
- 方法:
[a-zA-Z]+
- 方法:
2.2.2 案例二
要求写一个正则表达式,用来匹配邮箱,而邮箱规则如下:
- 结构:前缀@后缀
- 前缀:由大小写字母、数字、下划线、中划线等构成
- 后缀:由小写字母或数字构成,并以 .com 结尾
1 | 123@qq.com |
匹配邮箱的正则表达式:
- 匹配单个邮箱
- 方法:
^[a-zA-Z0-9_-]+@[a-z0-9]+.com$
- 方法:
- 匹配多个邮箱
- 方法:
[a-zA-Z0-9_-]+@[a-z0-9]+.com
- 方法:
2.3 Python 正则表达式用法
2.3.1 Re 模块
re.search( )
在字符串中搜索匹配正则表达式的第一个位置。
1 | import re |
re.match( )
用于从字符串的起始位置匹配正则表达式,如果起始位置匹配成功,则返回一个匹配对象;否则返回 None。
1 | import re |
Tips:
re.match()只从字符串的起始位置进行匹配,而re.search()则会在字符串中搜索匹配的部分,不限于起始位置。
再看个复杂点的正则表达式,进一步理解一下 match 和 search 函数的区别。
1 | # !/usr/bin/python3 |
re.findall( )
返回字符串中所有匹配正则表达式的子串。
1 | import re |
re.compile( )
re.complile() 用于编译正则表达式模式,生成一个正则表达式对象。这个对象可以被多次使用,从而提高效率。它接受一个字符串形式的正则表达式作为参数,并返回一个编译后的正则表达式对象。
除了前面提到的可以直接使用编译后的对象调用 findall 等方法之外,还可以设置一些标志参数来影响正则表达式的匹配行为。
常见的标志参数有:
re.IGNORECASE或re.I:使匹配对大小写不敏感。re.MULTILINE或re.M:多行模式,影响^和$的匹配行为。re.DOTALL或re.S:使.匹配包括换行符在内的所有字符。
1 | import re |
可以再来看一个分割字符串的例子。
1 | import re |
( ) 分组
使用括号 () 进行分组,可以提取匹配的子串。
1 | import re |
Tips:
这里的
r表示原始字符串,避免一些字符需要额外的转义。
re.sub( )
使用 re.sub() 函数可以进行替换操作。
1 | import re |
我们再结合前面的分组方法看一个更复杂点的例子,我想要将一串手机号的中间 4 个数字进行加密处理,我们
1 | import re |



