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

Python的异常机制

原创
作者头像
mariolu
修改2024-01-10 01:22:46
13800
代码可运行
修改2024-01-10 01:22:46
举报
运行总次数:0
代码可运行

一、异常与错误

Python机制设置了异常机制。异常指的是运行时程序遇到的可以被捕捉的错误。程序捕捉了异常,而不至于让程序运行错误而crash。异常增强了程序的运行可靠性。

我们来看个例子来对比下错误和异常的区别

  • 错误:
代码语言:python
代码运行次数:0
复制
import sys
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())

print("code reachs here.")
  • 异常:
代码语言:python
代码运行次数:0
复制
import sys
  
try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
except OSError as err:
    print("OS error:", err)
except ValueError:
    print("Could not convert data to an integer.")
except Exception as err:
    print(f"Unexpected {err=}, {type(err)=}")
    raise
    
print("code reachs here.")

我们可以看到运行了带异常捕获的例子,程序打印出了code reachs here

二、异常的分类

2.1 自定义异常

异常的基类Exception,一般我们继承Excpetion类来自定义异常类。

自定义异常类往往只提供一些属性保持简单,运行程序提取有关错误的信息。

大多数异常命名都以 “Error” 结尾,类似Python标准提供异常的命名。

比如说这种写法:

代码语言:python
代码运行次数:0
复制
class AppException(Exception):
    """ Application exception, will not be logged ass an error """
    pass
    
class UnknownSSIDError(AppException):
    def __init__(self, ssid):
        self.ssid = ssid
        super(UnknownSSIDError, self).__init__("Unknown ssid '%s'" % ssid)

2.2 内置异常分类

BaseException是所有异常的共同基类。它的一个子类Exception是所有非致命异常的基类。不是Exception的子类的异常通常不被处理。它们被用来指示程序应该终止,包括由sys.exit()引发的SystemExit,以及当用户希望中断程序时引发的 KeyboardInterrupt。

完整的Python的Excpetion见下图:

代码语言:javascript
复制
BaseException
 ├── BaseExceptionGroup
 ├── GeneratorExit
 ├── KeyboardInterrupt
 ├── SystemExit
 └── Exception
      ├── ArithmeticError
      │    ├── FloatingPointError
      │    ├── OverflowError
      │    └── ZeroDivisionError
      ├── AssertionError
      ├── AttributeError
      ├── BufferError
      ├── EOFError
      ├── ExceptionGroup [BaseExceptionGroup]
      ├── ImportError
      │    └── ModuleNotFoundError
      ├── LookupError
      │    ├── IndexError
      │    └── KeyError
      ├── MemoryError
      ├── NameError
      │    └── UnboundLocalError
      ├── OSError
      │    ├── BlockingIOError
      │    ├── ChildProcessError
      │    ├── ConnectionError
      │    │    ├── BrokenPipeError
      │    │    ├── ConnectionAbortedError
      │    │    ├── ConnectionRefusedError
      │    │    └── ConnectionResetError
      │    ├── FileExistsError
      │    ├── FileNotFoundError
      │    ├── InterruptedError
      │    ├── IsADirectoryError
      │    ├── NotADirectoryError
      │    ├── PermissionError
      │    ├── ProcessLookupError
      │    └── TimeoutError
      ├── ReferenceError
      ├── RuntimeError
      │    ├── NotImplementedError
      │    └── RecursionError
      ├── StopAsyncIteration
      ├── StopIteration
      ├── SyntaxError
      │    └── IndentationError
      │         └── TabError
      ├── SystemError
      ├── TypeError
      ├── ValueError
      │    └── UnicodeError
      │         ├── UnicodeDecodeError
      │         ├── UnicodeEncodeError
      │         └── UnicodeTranslateError
      └── Warning
           ├── BytesWarning
           ├── DeprecationWarning
           ├── EncodingWarning
           ├── FutureWarning
           ├── ImportWarning
           ├── PendingDeprecationWarning
           ├── ResourceWarning
           ├── RuntimeWarning
           ├── SyntaxWarning
           ├── UnicodeWarning
           └── UserWarning

三、异常处理

这段代码我们看到了几个关键动作。

  • 一个是raise 向外抛出了异常
  • 外面用try...except...捕获了异常。try语句可以有多个except 子句来为不同的异常指定处理程序。 但最多只有一个处理程序会被执行。 except 子句可以用带圆括号的元组来指定多个异常。此外try除了except还可以带else。
  • 捕获异常的优先级分别是各个的except从上到下去比对。且认为派生类异常会等于基类异常。所以在第一个for循环我们看到了输出,D-C-B。但是下一个for循环我们会看到输出,B-B-B。是因为第一个excpet B截获了所有的Exception。
代码语言:python
代码运行次数:0
复制
class B(Exception):
    pass

class C(B):
    pass

class D(C):
    pass

for cls in [B, C, D]:
    try:
        raise cls()
    except D:
        print("D")
    except C:
        print("C")
    except B:
        print("B")

for cls in [B, C, D]:
    try:
        raise cls()
    except B:
        print("B")
    except C:
        print("C")
    except D:
        print("D")

3.1 try...except...else

try ... except ... else ...finally...

  • finally子句是可选的,它是try语句结束前执行的最后一项任务。不论try语句是否触发异常,都会执行到finally子句。
  • else也是可选的。如果存在else,那么必须将else放在所有 except 子句 之后。 它适用于 try 子句 没有引发异常但又必须要执行的代码。 例如:
代码语言:javascript
复制
for arg in sys.argv[1:]:
    try:
        f = open(arg, 'r')
    except OSError:
        print('cannot open', arg)
    else:
        print(arg, 'has', len(f.readlines()), 'lines')
        f.close()

异常处理程序不仅会处理在 try 子句 中立刻发生的异常,还会处理在 try 子句 中调用(包括间接调用)的函数。

处理 Exception 最常见的模式是打印或记录异常,然后重新raise(允许调用者也处理异常):

3.2 添加异常追踪栈

异常是可以添加个性化信息的,比如说下面这个例子。我们可以通过args或者直接print这个异常输出个性化信息。

代码语言:python
代码运行次数:0
复制
try:
    raise Exception('spam', 'eggs')
except Exception as inst:
    print(type(inst))    # the exception type
    print(inst.args)     # arguments stored in .args
    print(inst)          # __str__ allows args to be printed directly,
                         # but may be overridden in exception subclasses
    x, y = inst.args     # unpack args
    print('x =', x)
    print('y =', y)

# output:
#<class 'Exception'>
#('spam', 'eggs')
#('spam', 'eggs')
#x = spam
#y = eggs

除了在Exception被创建的时候添加信息,我们还可以在Exception被处理的时候通过add_note方法追加信息。这时候我们添加这层堆栈的信息再raise出去给调用者捕获,那么这个Exception通过层层add_note就有个堆栈的全貌。

add_note(note) 方法接受一个字符串,并将其添加到异常的注释列表。标准的回溯在异常之后按照它们被添加的顺序呈现所有的注释。

代码语言:python
代码运行次数:0
复制
try:
    raise TypeError('bad type')
except Exception as e:
    e.add_note('Add some information')
    e.add_note('Add some more information')
    raise

#Traceback (most recent call last):
#  File "<stdin>", line 2, in <module>
#TypeError: bad type
#Add some information
#Add some more information

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、异常与错误
  • 二、异常的分类
    • 2.1 自定义异常
      • 2.2 内置异常分类
      • 三、异常处理
      • 3.1 try...except...else
        • 3.2 添加异常追踪栈
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
        http://www.vxiaotou.com