一、异常和错误
1.概念
Python有两种错误很容易辨认:语法错误和异常
Python 的语法错误或者称之为解析错误,是初学者经常碰到的,比如缺少冒号等
在程序运行过程中,总会遇到各种各样的错误,有的错误是程序编写有问题造成的,这种错误我们通常称之为bug,bug是必须修复的;有的错误是用户输入造成的,这种错误可以通过检查用户输入来做相应的处理;还有一类错误是完全无法在程序运行过程中预测的,比如写入文件的时候,磁盘满了,写不进去了,或者从网络抓取数据,网络突然断掉了,这类错误被称为异常,在程序中通常是必须处理的,否则,程序会因为各种问题终止并退出
#1.错误 #特点:直接报错【语法错误,编码规范】 # num = 10 # 3abc = "hello" #2.异常 #特点:当代码运行的时候会报错 try: list1 = [2, 4, 5, 5] print(list1[4]) except: print("出现了异常") print("over") #问题:如果代码中出现异常,但是未被处理,则程序会终止在出现异常处 #解决方案:如果出现异常,让程序继续执行
2.常见异常【面试题】
AttributeError 试图访问一个对象没有的属性,比如foo.x,但是foo没有属性x
IOError 输入/输出异常;基本上是无法打开文件
ImportError 无法引入模块或包;基本上是路径问题或名称错误
IndentationError 语法错误(的子类) ;代码没有正确对齐
IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
KeyError 试图访问字典里不存在的键
KeyboardInterrupt Ctrl+C被按下
NameError 使用一个还未被赋予对象的变量
SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了)
TypeError 传入对象类型与要求的不符合
UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,
导致你以为正在访问它
ValueError 传入一个调用者不期望的值,即使值的类型是正确的#1.ValueError #num = int(input("请输入:")) #ValueError: invalid literal for int() with base 10: 'abc' #2.NameError #print(num) #NameError: name 'num' is not defined #3.AttributeError class Person(): __slots__ = ("name",) p = Person() # p.age = 10 #AttributeError: 'Person' object has no attribute 'age' #print("abc".reverse()) #AttributeError: 'str' object has no attribute 'reverse' #4.KeyError # dict1 = {"a":10} # print(dict1["b"]) #KeyError: 'b' #5.UnboundLocalError # a = 1 # def func(): # a += 1 # func() #UnboundLocalError: local variable 'a' referenced before assignment #6.FileNotFoundError #f = open(r"a.txt","w",encoding="utf-8888") #FileNotFoundError: [Errno 2] No such file or directory: 'a.txt' #LookupError: unknown encoding: utf-8888 #7.ModuleNotFoundError #import aaa #ModuleNotFoundError: No module named 'aaa' #8.KeyboardInterrupt:当手动结束程序 # while True: # pass
3.异常处理方式
处理异常的本质:没有从根本上解决问题【修改代码】,只是将异常忽略,可以让后面的代码继续执行
3.1try-except-finally/else捕获【常用】
""" 语法: try: 语句1 except 错误标识码 as 变量: 语句2 except 错误标识码 as 变量: 语句3 .... else/finally: 语句n 说明: a.try块中的语句被称为代码监测区,将可能存在异常的代码书写在这里 b.如果try中的代码出现了异常,会匹配相应的except语句, 注意:此处的except并不是真正的将异常处理了,只是做了一个拦截 ,可以让后面的代码继续执行 c.else和finally语句可以根据具体的需求选择性的省略 """ #1.try-except ****** """ try: #注意1:将可能存在异常的代码书写在try块中检测起来 num = int(input("请输入一个数字:")) #注意2:e只是一个变量名,可以是任意的标识符,在编程语言中,异常为Exception,所以惯用e #注意3:e的类型是<class 'ValueError'>,e就是一个对象,相当于e = ValueError() except ValueError as e: print(e,type(e)) #注意4:当try中的代码出现异常,则执行相应的except语句 # 【如果没有匹配到相应的except,则异常还未被处理】, # 如果没有异常,则直接跳过except语句 #注意5:打印e获取的结果为字符串,因为异常类中已经重写了__str__函数 """ #2.try-except-except.... ****** """ #注意6:如果有多个except,至多只会执行一个,从上往下依次匹配,出现在最上面的最先被匹配 #注意7:不管try中有几个异常,最终都只会匹配一个except try: num = int(input("请输入一个数字:")) list1 = [2,5,56] print("列表中的元素:",list1[num]) #注意8:所有异常的父类是BaseException【Exception】, # 如果except中出现了父类,而且父类出现在最上面,会匹配所有的异常 except ValueError as e: print("value:",e) except Exception as e: print("父类:",e) except IndexError as e: print("index:",e) print("over") """ #3.try-except 父类 """ try: num = int(input("请输入一个数字:")) list1 = [2,5,56] print("列表中的元素:",list1[num]) except Exception as e: print("父类:",e) print("over") """ #4.try-except,省略类型 #说明:也可以匹配所有类型的异常,但是对于异常的描述缺失 """ try: num = int(input("请输入一个数字:")) list1 = [2,5,56] print("列表中的元素:",list1[num]) except: print("出现了异常") print("over") """ #5.try-except (错误码1,错误码2.。。。) #说明:匹配指定类型的异常 """ try: num = int(input("请输入一个数字:")) list1 = [2,5,56] print("列表中的元素:",list1[num]) except (IndexError,ValueError,AttributeError): print("出现了异常~~") print("over") """ #6.try-except-else #注意9:只有当try中的代码没有异常时,else才会被执行 """ try: num = int(input("请输入一个数字:")) list1 = [2,5,56] print("列表中的元素:",list1[num]) except ValueError as e: print(e) except IndexError as e: print(e) else: print("else被执行了") print("over") """ #7.try-except-finally #注意10:不管try中的代码是否存在异常,finally语句都会被执行 #使用场景:定义清理行为,表示无论在任何情况下都会执行的清理行为,比如:关闭文件,关闭数据库等 """ try: num = int(input("请输入一个数字:")) list1 = [2,5,56] print("列表中的元素:",list1[num]) except ValueError as e: print(e) except IndexError as e: print(e) finally: print("finally被执行了") print("over") """ #【面试题】当try-except-finally语句出现在函数中, # 如果try或者except语句中出现return,finally还是会正常执行 """ 注意: a.如果有异常:try-except-finally b.如果没有异常:try-finally """ """ def func(): try: num = int(input("请输入一个数字:")) list1 = [2, 5, 56] print("列表中的元素:", list1[num]) return except ValueError as e: print(e) return except IndexError as e: print(e) finally: print("finally被执行了") func() """ #8.如果函数中的代码可能存在异常,可以在函数中直接处理,也可以处理函数的调用 #方式一 """ def func(): try: num = int(input("请输入一个数字:")) list1 = [2, 5, 56] print("列表中的元素:", list1[num]) except ValueError as e: print(e) except IndexError as e: print(e) func() """ #方式二 def func(): num = int(input("请输入一个数字:")) list1 = [2, 5, 56] print("列表中的元素:", list1[num]) try: func() except ValueError as e: print(e) except IndexError as e: print(e)
3.2raise抛出
#异常对象出现的形式 #1.根据具体的问题出现:是一种可能性 try: num = int(input("输入:")) except ValueError as e: print(e) #2.可以手动创建一个异常的对象:百分百出现 try: raise ValueError("hello hello") except ValueError as e: print(e) #使用场景:一般用在自定义异常中
3.3assert断言
#assert:断言,预言 def func(num1,num2): #断言 #预测成功,则获取结果,预测失败,则打印预测的信息 #换句话说,用来测试一个表达式是否成立,如果返回值为假,就会触发一个新的异常,为AssertionError assert num2 != 0,"除数或者分母不能为0" return num1 / num2 print(func(10,0))
4.嵌套定义
""" try: 语句 except: 语句 finally: try: 语句 except: 语句 """ print("我要去拉萨") try: print("我准备坐飞机过去") raise Exception("由于大雾,飞机不能起飞") print("到拉萨了,拉萨真漂亮") except Exception as e: print(e) try: print("我准备坐火车过去") raise Exception("由于修路,火车停止") print("到拉萨了,拉萨真漂亮") except Exception as e: print(e) print("我骑自行车过去") print("到拉萨了,拉萨真漂亮")
5.自定义异常
#【面试题:书写自定义异常】 #1.自定义一个类,继承自BaseException或者Exception class MyException(BaseException): #2.书写构造函数,定义一个实例属性,表示当异常出现时异常的描述信息 def __init__(self,msg): #3.继承父类的异常机制【调用父类的构造函数】 super(MyException,self).__init__() self.msg = msg #4.重写__str__,返回异常的描述信息 def __str__(self): return self.msg #5.定义一个实例函数,如果出现了异常,则需要手动处理 def handle(self): #注意:在实际项目开发中,在此书是需要实际进行处理异常的操作 print("处理了异常") try: raise MyException("出现了异常") except MyException as e: print(e) #调用处理异常的函数 e.handle() #使用场景:使用系统的类解决不了生活中问题,则需要自定义异常
二、正则表达式
1.概述
正则表达式(英语:Regular Expression,在代码中常简写为regex、regexp或RE)使用单个字符串来描述、匹配一系列符合某个句法规则的字符串搜索模式。
- 搜索模式可用于文本搜索和文本替换。
- 正则表达式是由一个字符序列形成的搜索模式。
- 当你在文本中搜索数据时,你可以用搜索模式来描述你要查询的内容。
- 正则表达式可以是一个简单的字符,或一个更复杂的模式。
- 正则表达式可用于所有文本搜索和文本替换的操作
使用场景:
- 用于验证邮箱格式 手机号格式 密码格式等
- 爬虫时,使用正则抓取网页中指定内容
而在python中,通过内嵌集成re模块,程序媛们可以直接调用来实现正则匹配。正则表达式模式被编译成一系列的字节码,然后由用C编写的匹配引擎执行
Python 自1.5版本起增加了re 模块,它提供 Perl 风格的正则表达式模式。
re 模块使 Python 语言拥有全部的正则表达式功能
re 模块也提供了与这些方法功能完全一致的函数,这些函数使用一个模式字符串做为它们的第一个参数
2.案例
#封装函数,检测qq号的合法性 """ 分析: 1.纯数字 2.长度为5~11 3.开头不能为0 """ import re def isqq1(qq): #假设法 result = True if qq.isdigit(): if len(qq) <= 11 and len(qq) >= 5: if qq[0] == "0": result = False else: result = False else: result = False return result def isqq2(qq): # 假设法 result = True try: num = int(qq) if len(qq) <= 11 and len(qq) >= 5: if qq[0] == "0": #startswith() result = False else: result = False except ValueError as e: result = False return result if __name__ == "__main__": print(isqq1("244564774567588")) print(isqq2("2445647745688568")) #使用正则表达式判断扣扣好的合法性 print(re.match(r"^[1-9]\d{4,10}$","24456566")) print(re.match(r"^[1-9][0-9]{4,10}$", "24456566"))
3.使用
3.1单字符匹配
#单字符匹配
"""
. 匹配除换行符以外的任意字符
[0123456789] []是字符集合,表示匹配方括号中所包含的任意一个字符
[0-9] 匹配任意数字,类似[0123456789]
\d 匹配数字,效果同[0-9]
[good] 匹配good中任意一个字符
[a-z] 匹配任意小写字母
[A-Z] 匹配任意大写字母
[0-9a-zA-Z] 匹配任意的数字和字母
[0-9a-zA-Z_] 匹配任意的数字、字母和下划线
\w 匹配数字,字母和下划线,效果同[0-9a-zA-Z_]
[^good] 匹配除了good这几个字母以外的所有字符,中括号里的^称为脱字符,表示不匹配集合中的字符
[^0-9] 匹配所有的非数字字符
\D 匹配非数字字符,效果同[^0-9]
\W 匹配非数字,字母和下划线,效果同[^0-9a-zA-Z_]
\s 匹配任意的空白符(空格,回车,换行,制表,换页),效果同[ \r\n\t\f]
\S 匹配任意的非空白符,效果同[^ \f\n\r\t]
"""
"""
[] 不管其中书写了多少个字符,都只能匹配其中的一位
- 连接符,如1-9表示123456789,如果表示连续的数字或者字母都可以使用-表示
举例:[358]表示3,5,8,[3-8]表示345678
[^xxx] 脱字符,^写在[]中表示否定,直接写在正则字符串中表示匹配开头
\ 转义字符,字符可以是d和D,s和S,w和W,都表示单个字符的匹配
. 匹配除了换行符以外的任意字符
"""
import re
#re模块中常用的函数有:compile【编译】,match【匹配】,
# search/findall【搜索】,sub【替换】,split【分隔】等
#方式一
#re.xxxx(pattern,string,flags),pattern表示正则匹配规则
r0 = re.match(r"[a-z]","y")
print(r0)
#方式二
"""
result = re.compile(pattern)
pattern.xxxx(string)
"""
pattern = re.compile(r"[a-z]")
r1 = pattern.match("y")
print(r1)
#注意:match(),如果匹配上,则返回对象,如果匹配不上,则返回None
#如果能匹配上,通过group()获取匹配到的字符串
print(r0.group())
print(r1.group())
#. :可以匹配除了\n之外的所有的字符
r0 = re.match(r".","\n")
print(r0)
#[^xxx] :脱字符,表示否定
r0 = re.match(r"[^yang]","y")
print(r0)
#\d
r0 = re.match(r"\d","0")
print(r0)
r0 = re.match(r"[0-9]","0")
print(r0)
#\s,空白符[ \n\t\r\f]的匹配
r0 = re.match(r"\s","\n")
print(r0)
3.2多字符匹配
"""
-------------------匹配多个字符------------------------
说明:下方的x、y、z均为假设的普通字符,n、m(非负整数),不是正则表达式的元字符
(xyz) 匹配小括号内的xyz(作为一个整体去匹配)
x? 匹配0个或者1个x
x* 匹配0个或者任意多个x(.* 表示匹配0个或者任意多个字符(换行符除外))
x+ 匹配至少一个x
x{n} 匹配确定的n个x(n是一个非负整数)
x{n,} 匹配至少n个x
x{n,m} 匹配至少n个最多m个x。注意:n <= m
x|y |表示或,匹配的是x或y
"""
"""
() 分组,一个()内部的数据表示一个整体
? 匹配0个或者1个
* 匹配0个或者多个
+ 匹配1个或者多个
{} 匹配指定个数或者在指定区间内的个数的字符
| 正则1|正则2,只要正则1或者正则2中的任意一个匹配,则直接返回结果
"""
import re
#findall:根据指定的规则查找指定的字符串,将字符串中符合条件的子字符串全部获取出来,返回一个列表
print(re.findall(r"a+","aaaaaaaaaaaaaaa"))
print(re.findall(r"a?","aaaaaaaaaaaaaaa"))
print(re.findall(r"a*","aaaaaaaaaaaaaaa"))
print(re.findall(r"a{3}","aaaaaaaaaaaaaaaa")) #恰好
print(re.findall(r"a{3,}","aaaaaaaaaaaaaaa")) #至少
print(re.findall(r"a{3,5}","aaaaaaaaaaaaaaaaaa")) #区间
"""
['aaaaaaaaaaaaaaa']
['a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', '']
['aaaaaaaaaaaaaaa', '']
['aaa', 'aaa', 'aaa', 'aaa', 'aaa']
['aaaaaaaaaaaaaaa']
['aaaaa', 'aaaaa', 'aaaaa', 'aaa']
"""
#search:根据指定的规则查找指定的字符串,从左往右依次查找,只要匹配到一个,则停止查找
#注意:search的底层调用的是match,如果匹配上,则返回一个对象,匹配不上返回None
print(re.search(r"a+","aaaaaaaaaaaaaaa"))
print(re.search(r"a?","aaaaaaaaaaaaaaa"))
print(re.search(r"a*","aaaaaaaaaaaaaaa"))
print(re.search(r"a{3}","aaaaaaaaaaaaaaaa"))
print(re.search(r"a{3,}","aaaaaaaaaaaaaaa"))
print(re.search(r"a{3,5}","aaaaaaaaaaaaaaaaaa"))
"""
<re.Match object; span=(0, 15), match='aaaaaaaaaaaaaaa'>
<re.Match object; span=(0, 1), match='a'>
<re.Match object; span=(0, 15), match='aaaaaaaaaaaaaaa'>
<re.Match object; span=(0, 3), match='aaa'>
<re.Match object; span=(0, 15), match='aaaaaaaaaaaaaaa'>
<re.Match object; span=(0, 5), match='aaaaa'>
"""
3.3贪婪匹配和非贪婪匹配
import re
"""
贪婪匹配:尽可能多的匹配
非贪婪匹配:尽可能少的匹配
"""
#贪婪匹配
print(re.findall(r"\d+","2453645263436aaa-f5f5-3466bbv"))
print(re.findall(r"\d*","2453645263436aaa-f5f5-3466bbv"))
#非贪婪匹配
print(re.findall(r"\d?","2453645263436aaa-f5f5-3466bbv"))
"""
['2453645263436', '5', '5', '3466']
['2453645263436', '', '', '', '', '', '5', '', '5', '', '3466', '', '', '', '']
['2', '4', '5', '3', '6', '4', '5', '2', '6', '3', '4', '3', '6', '', '', '', '', '', '5', '', '5', '', '3', '4', '6', '6', '', '', '', '']
"""
#1.
print(re.findall(r"a\d+","a35475735673b"))
print(re.findall(r"a\d*","a35475735673b"))
"""
['a35475735673']
['a35475735673']
"""
print(re.findall(r"a\d+?","a35475735673b"))
print(re.findall(r"a\d*?","a35475735673b"))
"""
['a3']
['a']
"""
print("=" * 30)
#2
print(re.findall(r"\d+b","a35475735673b"))
print(re.findall(r"\d*b","a35475735673b"))
"""
['35475735673b']
['35475735673b']
"""
print(re.findall(r"\d+?b","a35475735673b"))
print(re.findall(r"\d*?b","a35475735673b"))
"""
['35475735673b']
['35475735673b']
"""
print("=" * 30)
#3
print(re.findall(r"a\d+b","a35475735673b"))
print(re.findall(r"a\d*b","a35475735673b"))
"""
['a35475735673b']
['a35475735673b']
"""
print(re.findall(r"a\d+?b","a354757356738989999b"))
print(re.findall(r"a\d*?b","a35475735673889999b"))
"""
['a35475735673b']
['a35475735673b']
"""
"""
结论:+或者*被称为贪婪匹配,?被称为非贪婪匹配
如果正则表达式的前面出现已知的限定条件,则在+或者*后面添加?则可以将贪婪匹配转换为非贪婪匹配
"""
3.4边界匹配
“”"
--------------锚字符(边界字符)-------------
^ 行首匹配,和在[]里的^不是一个意思
$ 行尾匹配
\A 匹配字符串开始,它和^的区别是,\A只匹配整个字符串的开头,即使在re.M模式下也不会匹配它行的行首
\Z 匹配字符串结束,它和$的区别是,\Z只匹配整个字符串的结束,即使在re.M模式下也不会匹配它行的行尾
\b 匹配一个单词的边界,也就是值单词和空格间的位置
\B 匹配非单词边界
"""
import re
print(re.findall(r"^today","today is a good day")) #startswith
print(re.findall(r"day$","today is a good day")) #endswith
print(re.findall(r"^today","today is a good day\ntoday is a good day\ntoday is a good day"))
print(re.findall(r"day$","today is a good day\ntoday is a good day\ntoday is a good day"))
"""
['today']
['day']
"""
print(re.findall(r"^today","today is a good day\ntoday is a good day\ntoday is a good day",re.M))
print(re.findall(r"day$","today is a good day\ntoday is a good day\ntoday is a good day",re.M))
"""
['today', 'today', 'today']
['day', 'day', 'day']
"""
print(re.findall(r"\Atoday","today is a good day\ntoday is a good day\ntoday is a good day",re.M))
print(re.findall(r"day\Z","today is a good day\ntoday is a good day\ntoday is a good day",re.M))
"""
['today']
['day']
"""
#结论:re.M只对^和$起作用
#\b和\B
#\b匹配边界,\B匹配非边界
print(re.search(r"er\b","never"))
print(re.search(r"er\b","neraa"))
print(re.search(r"er\B","never"))
print(re.search(r"er\B","neraa"))
"""
<re.Match object; span=(3, 5), match='er'>
None
None
<re.Match object; span=(1, 3), match='er'>
"""