|
我年纪轻轻就学会了Python编程
本章目录
一、异常
在程序的运行过程中,发生异常或者错误是非常正常的,一般来说,编程语言都会设定一些特有的异常和自定义异常,我们需要捕捉它们,
这样就可以知道是否有错,出错的原因是什么,以及如果出现错误我们应该怎么修复跳过等,甚至我们需要在特定的情况下需要引发一些异常。
Python常见的异常有以下几种:
- AssertionError:断言语句失败(assert 后的条件为假)
- AttributeError:访问的对象属性不存在
- ImportError:无法导入模块或者对象,主要是路径有误或名称错误
- IndentationError:代码没有正确对齐,主要是缩进错误
- IndexError:下标索引超出序列范围
- IOError:输入/输出异常,主要是无法打开文件
- KeyError:访问字典里不存在的键
- NameError:访问一个未声明的变量
- OverflowError:数值运算超出最大限制
- SyntaxError:python语法错误
- TabError:Tab和空格混用
- TypeError:不同类型数据之间的无效操作(传入对象类型与要求的不符合)
- ValueError:传入无效的值,即使值的类型是正确的
- ZeroDivisionError:除法运算中除数0 或者 取模运算中模数为0
- Exception:自定义异常
一旦程序发生异常,表明该程序在执行时出现了非正常的情况,无法再执行下去。默认情况下,程序会终止退出。
捕获异常
Python提供以下关键语句来捕捉异常:
try:
处理代码块
except 异常: ### 不写异常表示捕捉所有异常
发生异常的代码块
a = 1
b = '2'
c = a + b
output:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_9612/2197615168.py in <module>
1 a = 1
2 b = &#39;2&#39;
----> 3 c = a + b
TypeError: unsupported operand type(s) for +: &#39;int&#39; and &#39;str&#39;
try:
a = 1
b = &#39;2&#39;
c = a+b
except:
c = 3
print(c)
output:
3
### 捕捉特定异常,这样就可以方便我们差错
try:
a = 1
b = &#39;2&#39;
c = a+b
except TypeError:
c = 3
print(c)
output:
3加上关键字else表示不发生异常运行
try:
处理代码块
except 异常: ### 不写异常表示捕捉所有异常
发生异常的代码块
else:
不发生异常处理代码块else一般可以不写可以通过缩进来进行后面的代码块区分
try:
a = 1
b = &#39;2&#39;
c = a+b
except TypeError:
c = 3
else:
print(c)
try:
a = 1
b = 2
c = a+b
except TypeError:
c = 3
else:
print(c)
output:
3加上换剪子finally表示无论有没有异常都会执行的代码块
try:
处理代码块
except 异常: ### 不写异常表示捕捉所有异常
发生异常的代码块
else:
不发生异常处理代码块
finally:
无论有么有异常都执行的代码块
try:
a = 1
b = &#39;2&#39;
c = a+b
except TypeError:
c = 3
else:
c = 4
finally:
print(c)
output:
3泛华异常
很多情况下,我们根本不知道会发生什么具体类型的异常,这时候我们使用关键字:Exception表示所有异常,并且提供关键字:as,可以重命名该异常
try:
处理代码块
except Exception as e: ### 不写异常表示捕捉所有异常
print(e)
try:
a = 1
b = &#39;2&#39;
c = a+b
except Exception as e:
print(f&#39;异常信息:{e}&#39;)
output:
异常信息:unsupported operand type(s) for +: &#39;int&#39; and &#39;str&#39;更详细的捕捉异常
捕捉异常的本质是为了让我们发现并修改错误,有时候代码太多,调用太繁琐不是很容易发现,这时候需要具体到哪一行代码发生了错误,
Python提供内置模块:traceback来详细的打印异常,常用方法有:
- traceback.print_exc():打印具体异常信息
- traceback.format_exc():返回异常信息字符串方便二次处理
import traceback
try:
a = 1
b = &#39;2&#39;
c = a+b
except:
traceback.print_exc()
output:
Traceback (most recent call last):
File &#34;C:\Users\DELL\AppData\Local\Temp/ipykernel_9612/3288308381.py&#34;, line 6, in <module>
c = a+b
TypeError: unsupported operand type(s) for +: &#39;int&#39; and &#39;str&#39;
try:
a = 1
b = &#39;2&#39;
c = a+b
except:
info = traceback.format_exc()
print(info)
output:
Traceback (most recent call last):
File &#34;C:\Users\DELL\AppData\Local\Temp/ipykernel_9612/511410514.py&#34;, line 4, in <module>
c = a+b
TypeError: unsupported operand type(s) for +: &#39;int&#39; and &#39;str&#39;自定义引发异常
Python提供关键字:raise,搭配:Exception,用来引发自定义异常
raise Exception(&#39;异常字符串&#39;)
a = 1
raise Exception(&#39;这是一个自定义的异常&#39;)
output:
---------------------------------------------------------------------------
Exception Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_9612/1205731023.py in <module>
1 a = 1
----> 2 raise Exception(&#39;这是一个自定义的异常&#39;)
Exception: 这是一个自定义的异常二、调试
一般来说,程序一次性写完并正常运行的概率非常小,经常发生某些bug,总会有各种bug需要修复,这可能就是导致脱发的根本原因,
有些bug看看报错信息就知道怎么解决,有些bug很复杂,我们需要知道哪里出了错,这时候就需要一套完整的调试程序修复bug
最常用的方法有:
- try...except:...:捕捉异常信息
- print():简单粗暴打印各种变量信息
- assert:断言辅助查看
使用:print
def sums(a,b):
return a+b
sums(1,&#39;2&#39;)
output:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_9612/440557491.py in <module>
2 return a+b
3
----> 4 sums(1,&#39;2&#39;)
~\AppData\Local\Temp/ipykernel_9612/440557491.py in sums(a, b)
1 def sums(a,b):
----> 2 return a+b
3
4 sums(1,&#39;2&#39;)
TypeError: unsupported operand type(s) for +: &#39;int&#39; and &#39;str&#39;
def sums(a,b):
print(f&#39;a: {type(a)}&#39;)
print(f&#39;b: {type(b)}&#39;)
return a+b
sums(1,&#39;2&#39;)
output:
a: <class &#39;int&#39;>
b: <class &#39;str&#39;>
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_9612/2972384813.py in <module>
6 return a+b
7
----> 8 sums(1,&#39;2&#39;)
~\AppData\Local\Temp/ipykernel_9612/2972384813.py in sums(a, b)
4 print(f&#39;b: {type(b)}&#39;)
5
----> 6 return a+b
7
8 sums(1,&#39;2&#39;)
TypeError: unsupported operand type(s) for +: &#39;int&#39; and &#39;str&#39;使用断言:assert
assert isinstance(b,int)
def sums(a,b):
assert isinstance(a,int)
assert isinstance(b,int)
return a+b
sums(1,&#39;2&#39;)
output:
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_9612/2712414290.py in <module>
----> 1 assert isinstance(b,int)
2
3 def sums(a,b):
4
5 assert isinstance(a,int)
AssertionError:适当的加上print和assert可以方便修复bug,但一定要记住,程序正式上线一定要注释掉这些地方,因为它们非常影响运行速度
三、单元调试
上述调试其实只是对一句代码进行调试,Python是一个函数式编程,有很多的函数,类,第三方模块等需要测试工作,这时候就需要单元调试
比如Python有个内置函数:abs(),正常返回如下:
- 输入正数:返回和输入相同
- 输入负数:返回和输入相反
- 输入0:返回0
- 输入非数值类型,如:None、str等,输出异常:TypeError
如果把这个函数的四个用例放在一个测试模块,那就是一套完整的单元调试,
假如通过单元调试,则说明函数正常工作;
假如不通过单元调试,则说明函数存在bug。
Python提供内置模块:unittest进行单元调试
# %load ./examples/testing.py
import unittest
class TestABS(unittest.TestCase):
def test_example1(self):
self.assertEqual(abs(1),1)
def test_example2(self):
self.assertEqual(abs(-1),1)
def test_example3(self):
self.assertEqual(abs(0),0)
def test_example4(self):
a = &#39;1&#39;
with self.assertRaises(TypeError):
abs(a)
if __name__ == &#39;__main__&#39;:
unittest.main()
%%cmd
python ./examples/testing1.py
output:
Microsoft Windows [版本 10.0.22598.200]
(c) Microsoft Corporation。保留所有权利。
E:\notebook\B站\花卷学Python\8. Python编程:异常与调试>python ./examples/testing1.py
E:\notebook\B站\花卷学Python\8. Python编程:异常与调试>
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK比如我们调试一个自定义的类
# %load ./examples/testing1.py
class Student(object):
def __init__(self, name: str = &#39;&#39;, score: int = 0):
self.name = name
self.score = score
def get_grade(self):
if self.score > 80:
return &#39;优秀&#39;
else:
return &#39;良好&#39;
import unittest
class TestABS(unittest.TestCase):
def test_greater_80(self):
a = Student(&#39;a&#39;,90)
self.assertEqual(a.get_grade(),&#39;优秀&#39;)
def test_less_80(self):
a = Student(&#39;a&#39;,70)
self.assertEqual(a.get_grade(),&#39;良好&#39;)
if __name__ == &#39;__main__&#39;:
unittest.main()
%%cmd
python ./examples/testing1.py
output:
Microsoft Windows [版本 10.0.22598.200]
(c) Microsoft Corporation。保留所有权利。
E:\notebook\B站\花卷学Python\8. Python编程:异常与调试>python ./examples/testing1.py
E:\notebook\B站\花卷学Python\8. Python编程:异常与调试>
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK四、文档调试
假如你经常看Python的源码,会发现很多函数或者类都提供了文档,里面包含该函数或者类的交互式运行方式,
一般来说,当我们使用一个陌生的函数或者类,看一下文档粘贴复制就可以直接使用它了,
比如:
def myabs(a):
&#34;&#34;&#34;
绝对值函数
Example:
>>> myabs(1)
1
>>> myabs(-1)
1
>>> myabs(0)
0
>>> myabs(&#39;1&#39;)
TypeError Traceback (most recent call last)
...
TypeError: bad operand type for abs(): &#39;str&#39;
&#34;&#34;&#34;
res = a if a >= 0 else -a
return res
print(myabs.__doc__)
output:
绝对值函数
Example:
>>> myabs(1)
1
>>> myabs(-1)
1
>>> myabs(0)
0
>>> myabs(&#39;1&#39;)
TypeError Traceback (most recent call last)
...
TypeError: bad operand type for abs(): &#39;str&#39;该文档非常明确的告诉你:myabs函数怎么运行
Python提供内置模块:doctest直接提取文档并执行测试
doctest严格按照Python交互式命令行的输入和输出来判断测试结果是否正确。只有测试异常的时候,可以用...表示中间一大段烦人的输出。
比如我们测试一下我们的:myabs函数
# %load ./examples/testing2.py
def myabs(a):
&#34;&#34;&#34;
绝对值函数
Example:
>>> myabs(1)
1
>>> myabs(-1)
1
>>> myabs(0)
0
>>> myabs(&#39;1&#39;)
TypeError Traceback (most recent call last)
...
TypeError: bad operand type for abs(): &#39;str&#39;
&#34;&#34;&#34;
res = a if a >= 0 else -a
return res
if __name__ == &#34;__main__&#34;:
import doctest
doctest.testmod()
%%cmd
python ./examples/testing2.py
output:
Microsoft Windows [版本 10.0.22598.200]
(c) Microsoft Corporation。保留所有权利。
E:\notebook\B站\花卷学Python\8. Python编程:异常与调试>python ./examples/testing2.py
**********************************************************************
File &#34;E:\notebook\B站\花卷学Python\8. Python编程:异常与调试\examples\testing2.py&#34;, line 16, in __main__.myabs
Failed example:
myabs(&#39;1&#39;)
Exception raised:
Traceback (most recent call last):
File &#34;D:\anaconda\lib\doctest.py&#34;, line 1336, in __run
exec(compile(example.source, filename, &#34;single&#34;,
File &#34;<doctest __main__.myabs[3]>&#34;, line 1, in <module>
myabs(&#39;1&#39;)
File &#34;E:\notebook\B站\花卷学Python\8. Python编程:异常与调试\examples\testing2.py&#34;, line 21, in myabs
res = a if a >= 0 else -a
TypeError: &#39;>=&#39; not supported between instances of &#39;str&#39; and &#39;int&#39;
**********************************************************************
1 items had failures:
1 of 4 in __main__.myabs
***Test Failed*** 1 failures.
E:\notebook\B站\花卷学Python\8. Python编程:异常与调试>赞赏
读后若有收获,可以微信请作者喝咖啡:
 |
|