简介

和其余的语言一样,Python中也有异样和谬误。在 Python 中,所有异样都是 BaseException 的类的实例。 明天咱们来具体看一下Python中的异样和对他们的解决形式。

Python中的内置异样类

Python中所有异样类都来自BaseException,它是所有内置异样的基类。

尽管它是所有异样类的基类,然而对于用户自定义的类来说,并不举荐间接继承BaseException,而是继承Exception.

先看下Python中异样类的构造关系:

BaseException +-- SystemExit +-- KeyboardInterrupt +-- GeneratorExit +-- Exception      +-- StopIteration      +-- StopAsyncIteration      +-- ArithmeticError      |    +-- FloatingPointError      |    +-- OverflowError      |    +-- ZeroDivisionError      +-- AssertionError      +-- AttributeError      +-- BufferError      +-- EOFError      +-- 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      +-- SyntaxError      |    +-- IndentationError      |         +-- TabError      +-- SystemError      +-- TypeError      +-- ValueError      |    +-- UnicodeError      |         +-- UnicodeDecodeError      |         +-- UnicodeEncodeError      |         +-- UnicodeTranslateError      +-- Warning           +-- DeprecationWarning           +-- PendingDeprecationWarning           +-- RuntimeWarning           +-- SyntaxWarning           +-- UserWarning           +-- FutureWarning           +-- ImportWarning           +-- UnicodeWarning           +-- BytesWarning           +-- ResourceWarning

其中BaseExceptionExceptionArithmeticErrorBufferErrorLookupError 次要被作为其余异样的基类。

语法错误

在Python中,对于异样和谬误通常能够分为两类,第一类是语法错误,又称解析谬误。也就是代码还没有开始运行,就产生的谬误。

其产生的起因就是编写的代码不合乎Python的语言标准:

>>> while True print('Hello world')  File "<stdin>", line 1    while True print('Hello world')                   ^SyntaxError: invalid syntax

下面代码起因是 print 后面少了 冒号。

异样

即便咱们的程序合乎python的语法标准,然而在执行的时候,依然可能发送谬误,这种在运行时发送的谬误,叫做异样。

看一下上面的异样:

>>> 10 * (1/0)Traceback (most recent call last):  File "<stdin>", line 1, in <module>ZeroDivisionError: division by zero>>> 4 + spam*3Traceback (most recent call last):  File "<stdin>", line 1, in <module>NameError: name 'spam' is not defined>>> '2' + 2Traceback (most recent call last):  File "<stdin>", line 1, in <module>TypeError: Can't convert 'int' object to str implicitly

异样解决

程序产生了异样之后该怎么解决呢?

咱们能够应用try except 语句来捕捉特定的异样。

>>> while True:...     try:...         x = int(input("Please enter a number: "))...         break...     except ValueError:...         print("Oops!  That was no valid number.  Try again...")...

下面代码的执行流程是,首先执行try中的子语句,如果没有异样产生,那么就会跳过except,并实现try语句的执行。

如果try中的子语句中产生了异样,那么将会跳过try子句中的前面局部,进行except的异样匹配。如果匹配胜利的话,就会去执行except中的子语句。

如果产生的异样和 except 子句中指定的异样不匹配,则将其传递到内部的 try语句中。

一个try中能够有多个except 子句,咱们能够这样写:

    try:        raise cls()    except D:        print("D")    except C:        print("C")    except B:        print("B")

一个except也能够带多个异样:

... except (RuntimeError, TypeError, NameError):...     pass

except 子句还能够省略异样名,用来匹配所有的异样:

import systry:    f = open('myfile.txt')    s = f.readline()    i = int(s.strip())except OSError as err:    print("OS error: {0}".format(err))except ValueError:    print("Could not convert data to an integer.")except:    print("Unexpected error:", sys.exc_info()[0])    raise

try ... except语句有一个可选的 else 子句,在应用时必须放在所有的 except 子句前面。对于在 try 子句不引发异样时必须执行的代码来说很有用。 例如:

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()

except能够指定异样变量的名字 instance ,这个变量代表这个异样实例。

咱们能够通过instance.args来输入异样的参数。

同时,因为异样实例定义了 __str__(),所以能够间接应用print来输入异样的参数。而不须要应用 .args

咱们看一个例子:

>>> try:...     raise Exception('spam', 'eggs')... except Exception as inst:...     print(type(inst))    # the exception instance...     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)...<class 'Exception'>('spam', 'eggs')('spam', 'eggs')x = spamy = eggs

下面的例子中,咱们在try字句中抛出了一个异样,并且指定了2个参数。

抛出异样

咱们能够应用raise语句来抛出异样。

>>> raise NameError('HiThere')Traceback (most recent call last):  File "<stdin>", line 1, in <module>NameError: HiThere

raise的参数是一个异样,这个异样能够是异样实例或者是一个异样类。

留神,这个异样类必须是Exception的子类。

如果传递的是一个异样类,那么将会调用无参构造函数来隐式实例化:

raise ValueError  # shorthand for 'raise ValueError()'

如果咱们捕捉了某些异样,然而又不想去解决,那么能够在except语句中应用raise,从新抛出异样。

>>> try:...     raise NameError('HiThere')... except NameError:...     print('An exception flew by!')...     raise...An exception flew by!Traceback (most recent call last):  File "<stdin>", line 2, in <module>NameError: HiThere

异样链

如果咱们通过except捕捉一个异样A之后,能够通过raise语句再次抛出一个不同的异样类型B。

那么咱们看到的这个异样信息就是B的信息。然而咱们并不知道这个异样B是从哪里来的,这时候,咱们就能够用到异样链。

异样链就是抛出异样的时候,应用raise from语句:

>>> def func():...     raise IOError...>>> try:...     func()... except IOError as exc:...     raise RuntimeError('Failed to open database') from exc...Traceback (most recent call last):  File "<stdin>", line 2, in <module>  File "<stdin>", line 2, in funcOSErrorThe above exception was the direct cause of the following exception:Traceback (most recent call last):  File "<stdin>", line 4, in <module>RuntimeError: Failed to open database

下面的例子中,咱们在捕捉IOError之后,又抛出了RuntimeError,通过应用异样链,咱们很清晰的看出这两个异样之间的关系。

默认状况下,如果异样是从except 或者 finally 中抛出的话,会主动带上异样链信息。

如果你不想带上异样链,那么能够 from None

try:    open('database.sqlite')except IOError:    raise RuntimeError from NoneTraceback (most recent call last):  File "<stdin>", line 4, in <module>RuntimeError

自定义异样

用户能够继承 Exception 来实现自定义的异样,咱们看一些自定义异样的例子:

class Error(Exception):    """Base class for exceptions in this module."""    passclass InputError(Error):    """Exception raised for errors in the input.    Attributes:        expression -- input expression in which the error occurred        message -- explanation of the error    """    def __init__(self, expression, message):        self.expression = expression        self.message = messageclass TransitionError(Error):    """Raised when an operation attempts a state transition that's not    allowed.    Attributes:        previous -- state at beginning of transition        next -- attempted new state        message -- explanation of why the specific transition is not allowed    """    def __init__(self, previous, next, message):        self.previous = previous        self.next = next        self.message = message

finally

try语句能够跟着一个finally语句来实现一些收尾操作。

>>> try:...     raise KeyboardInterrupt... finally:...     print('Goodbye, world!')...Goodbye, world!KeyboardInterruptTraceback (most recent call last):  File "<stdin>", line 2, in <module>

finally 子句将作为 try 语句完结前的最初一项工作被执行, 无论try中是否产生异样,finally语句中的代码都会被执行。

如果 finally 子句中蕴含一个 return 语句,则返回值将来自 finally 子句的某个 return 语句的返回值,而非来自 try 子句的 return 语句的返回值。

>>> def bool_return():...     try:...         return True...     finally:...         return False...>>> bool_return()False
本文已收录于 http://www.flydean.com/09-python-error-exception/

最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!

欢送关注我的公众号:「程序那些事」,懂技术,更懂你!