前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python升级之路( Lv8 ) 异常机制

Python升级之路( Lv8 ) 异常机制

作者头像
时间静止不是简史
发布2022-06-28 09:38:18
3800
发布2022-06-28 09:38:18
举报
文章被收录于专栏:Java探索之路Java探索之路

Python系列文章目录

第一章 Python 入门

第二章 Python基本概念

第三章 序列

第四章 控制语句

第五章 函数

第六章 面向对象基础

第七章 面向对象深入

第八章 异常机制


异常机制

前言

在本章, 我们首先会了解什么是异常: 软件程序在运行过程中,可能会遇到能使其不能正常运行的问题,我们称之为异常,英文是: Exception 然后, 我们会了解捕获异常的四种结构方式, 再然后, 我们梳理常见放的异常 再然后, 我们补充其他关于异常相关的问题, 最后, 我们通过使用 Pycharm 来体会异常的调试过程


一、异常是什么

程序在运行过程中发生的意外情况,称为异常, 程序运行时一旦出现了异常,将会导致程序立即终止,异常之后的代码将无法继续执行,所以需要对异常进行处理

异常机制本质:

  • 当程序出现异常,程序安全的退出、处理完后继续执行的机制

python中,引进了很多用来描述和处理异常的类,称为异常类. 异常类定义中包含了该类异常的信息和对异常进行处理的方法.

下面较为完整的展示了python中内建异常类的继承层次:

解决思路

异常解决的关键:定位 当发生异常时,解释器会报相关的错误信息,并会在控制台打印出相关错误信息. 我们只需按照从上到下的顺序即可追溯(Trackback)错误发生的过程,最终定位引起错误的哪一行代码.

实操代码

代码语言:javascript
复制
# 测试简单的0不能做除数异常
# 因为如果假设成立, 则说明 3/0=0 => 可以推导 0*0=3, 因为结果不成立, 因此假设不成立
# a = 3/0

def a():
    print("run in a() start! ")
    num = 1/0
    print("run in a() end! ")


def b():
    print("run in b() start! ")
    a()
    print("run in b() end! ")


def c():
    print("run in c() start! ")
    b()
    print("run in c() end! ")


print("step1")
c()
print("step2")

结果输出

从打印输出结果来看, 最底层的方法(eg: a())出错之后, 会在上层调用的方法位置处抛出异常. 因为错误信息以栈的形式输出, 因此最顶层的调用因为先打印, 所以会先被我们看到. 因此对底层/最有用的信息一般位于最下面.


二、try和except结构

try…一个except结构

这种结构是最常见, 也是最常用的结构

语法结构

代码语言:javascript
复制
try:
 被监控的可能引发异常的语句块
except  BaseException [as  e]:
 异常处理语句块

注意事项:

  • try 块包含着可能引发异常的代码, except 块则用来捕捉和处理发生的异常
  • 执行的时候,如果 try 块中没有引发异常,则跳过 ecept 块继续执行后续代码
  • 执行的时候,如果 try 块中发生了异常,则跳过 try 块中的后续代码,跳到相应的 except 块中处理异常. 异常处理完后,继续执行后续代码

实操代码

代码语言:javascript
复制
def a():
    print("run in a() start! ")
    try:
        num = 1 / 0
    except BaseException as e:
        print("捕获异常之后执行此处代码")
    print("run in a() end! ")


def b():
    print("run in b() start! ")
    a()
    print("run in b() end! ")


def c():
    print("run in c() start! ")
    b()
    print("run in c() end! ")


print("step1")
c()
print("step2")

结果输出

try…多个except结构

try…except 的结构可以捕获所有的异常,工作中也很常见. 但是,一般建议尽量捕获可能出现的多个异常(按照先子类后父类的顺序),并且针对性写出异常处理代码 为了避免遗漏可能出现的异常,可以在最后增加 BaseException 。结构如下

语法结构

代码语言:javascript
复制
try:
 被监控的、可能引发异常的语句块
except  Exception1:
 处理Exception1的语句块
except  Exception2:
 处理Exception2的语句块
[...]
except  BaseException:
 处理可能遗漏的异常的语句块

实操代码

代码语言:javascript
复制
try:
    a = input("请输入被除数: ")
    b = input("请输入除数: ")
    result = float(a)/float(b)
    print(result)

except ZeroDivisionError:
    print("异常: 0不能做除数")
except ValueError:
    print("异常: 输入的必须是数值类型!")
except BaseException as e:
    print(e)
    print(type(e))

结果输出

try…except…else结构

在 try…except…else 结构的基础上增加了 else 块 . 如果 try 块中没有抛出异常,则执行else 块. 如果 try 块中抛出异常,则执行 except 块,不执行 else 块.

语法结构

代码语言:javascript
复制
try:
 被监控的可能引发异常的语句块
except  BaseException [as  e]:
 异常处理语句块
else:
 没有抛出异常时执行的语句块

实操代码

代码语言:javascript
复制
try:
    a = input("请输入被除数: ")
    b = input("请输入除数: ")
    result = float(a)/float(b)
except BaseException as e:
    print(e)
else:
    print("两数相除, 结果是:", result)

结果输出

try…except…finally结构

try…except…finally 结构中, finally 块无论是否发生异常都会被执行, 通常用来释放 try 块中申请的资源

语法结构

代码语言:javascript
复制
try:
 被监控的可能引发异常的语句块
except  BaseException [as  e]:
 异常处理语句块
finally:
 无论是否捕获异常都会执行的语句块

实操代码

代码语言:javascript
复制
try:
    a = input("请输入被除数: ")
    b = input("请输入除数: ")
    result = float(a)/float(b)
except BaseException as e:
    print(e)
else:
    print("两数相除, 结果是:", result)
finally:
    print("我是finally中的语句, 无论发生异常与否, 都执行!")

输出结果

实操代码2

代码语言:javascript
复制
try:
    f = open("d:/a.txt",'r')
    content = f.readline()
    print(content)
except BaseException as e:
    print(e)
finally:
    f.close()       #释放资源. 此处也可能会发生异常。若发生异常,则程序终止,不会继续往下执行
print("step4")

三、常见异常

异常汇总


常见异常举例

代码语言:javascript
复制
# Python中的异常都派生自 BaseException 类, 我们测试和列出常见的一些异常, 方便初学者掌握

# 1. SyntaxError :语法错误 | SyntaxError: invalid syntax. Perhaps you forgot a comma?
# int a =3

# 2. NameError :尝试访问一个没有申明的变量 | NameError: name 'a' is not defined
# print(a)

# 3. ZeroDivisionError :除数为0错误(零除错误) | ZeroDivisionError: division by zero
# a = 3 / 0

# 4. ValueError :数值错误 | ValueError: could not convert string to float: 'skyII'
# float("skyII")

# 5. TypeError :类型错误 | TypeError: unsupported operand type(s) for +: 'int' and 'str'
# 123+"abc"

# 6. AttributeError :访问对象的不存在的属性 | AttributeError: 'int' object has no attribute 'sayhi'
# a = 100
# a.sayhi()

# 7. IndexError :索引越界异常 | IndexError: list index out of range
# a = [4, 5, 6]
# a[10]

# 8. KeyError :字典的关键字不存在 | KeyError: 'salary'
a = {'name': "sari", 'age': 18}
a['salary']

四、其他异常相关问题

return语句和异常处理问题

由于 return 有两种作用:结束方法运行、返回值. 我们一般不把 return放到异常处理结构中,而是放到方法最后.

实操代码

一般不要将return语句放到try、except、else、finally块中, 会发生一些意想不到的错误. 建议放到方法最后 如上面代码, 这种写法就会导致无论是否正确, 都会导致 try内的return无法执行而去执行 finally 内的语句

代码语言:javascript
复制
def testException():
    try:
        a = input("请输入被除数: ")
        b = input("请输入除数: ")
        result = float(a) / float(b)
        return result
    except BaseException as e:
        print(e)
        return "a"
    finally:
        print("我是finally中的语句, 无论发生异常与否, 都执行!")
        return "b"
	# return "b" # 正常情况应该放到这里
print(testException())

结果输出

with上下文管理

finally 块由于是否发生异常都会执行,通常我们作为放释放资源的代码. 其实,我们可以通过 with 上下文管理,更方便的实现释放资源的操作. with 上下文管理可以自动管理资源,在 with 代码块执行完毕后自动还原进入该代码之前的现场或上下文. 不论何种原因跳出 with块,不论是否有异常,总能保证资源正常释放. 极大的简化了工作,在文件操作、网络通信相关的场合非常常用.

语法结构

代码语言:javascript
复制
with  context_expr [ as  var]:
 语句块

实操代码

代码语言:javascript
复制
# 【示例】 with 上下文管理文件操作
with open("d:/dd.txt") as f:
    for line in f:
        print(line)

traceback模块和生成异常日志

我们可以利用 traceback.print_exc(file=f), 将异常日志输出到日志文件中

代码语言:javascript
复制
# traceback模块和生成异常日志
import traceback

try:
    print("step1")
    num = 1 / 0
except:
    # traceback.print_exc()  # 直接输出错误调用记录
    with open("d:/a.log", "a") as f:    # 使用 traceback 将异常信息写入日志文件
         traceback.print_exc(file=f)

自定义异常类

程序开发中,有时候我们也需要自己定义异常类. 自定义异常类一般都是运行时异常,通常继承 Exception 或其子类即可. 命名一般以Error 、 Exception 为后缀. 自定义异常由 raise 语句主动抛出.

实操代码

代码语言:javascript
复制
# 【示例】自定义异常类和raise语句
class AgeError(Exception):
    def __init__(self, errorInfo):
        Exception.__init__(self)
        self.errorInfo = errorInfo

    def __str__(self):
        return str(self.errorInfo) + ", 年龄错误! 应该在 1-150之间!"


# 测试代码
if __name__ == "__main__":  # 如果为True, 则模块是作为独立文件运行, 可以执行测试代码
    age = int(input("输入一个年龄: "))
    if age < 1 or age > 150:
        raise AgeError(age)
    else:
        print("正常的年龄: ", age)

结果输出


五、Pycharm开发环境的调试(debug)

程序运行到此处,暂时挂起,停止执行。我们可以详细在此时观察程序的运行情况,方便做出进一步的判断

调试步骤

  1. 设置断点: 在行号后面单击即可增加断点。在断点上再单击即可取消断点
  1. 进入调试视图 我们通过如下三种方式都可以进入调试视图: 单击工具栏上的按钮 / 右键单击编辑区,点击: debug ‘模块名’ / 快捷键: shift+F9
  1. 进入调试视图后,布局如下: 左侧为“浏览帧”:调试器列出断点处,当前线程正在运行的方法,每个方法对应一个“栈帧”. 最上面是当前断点所处的方法. 变量值观察区: 调试器列出了断点处所在方法相关的变量值. 我们可以通过它,查看变量的值的变化.
  1. 调试操作区

我们通过上图中的按钮进行调试操作,它们的含义如下:


本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-06-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Python系列文章目录
    • 异常机制
    • 前言
    • 一、异常是什么
      • 解决思路
      • 二、try和except结构
        • try…一个except结构
          • try…多个except结构
            • try…except…else结构
              • try…except…finally结构
              • 三、常见异常
                • 异常汇总
                  • 常见异常举例
                  • 四、其他异常相关问题
                    • return语句和异常处理问题
                      • with上下文管理
                        • traceback模块和生成异常日志
                          • 自定义异常类
                          • 五、Pycharm开发环境的调试(debug)
                          领券
                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档