乐趣区

关于python:Python基础之Python中的异常和错误

简介

和其余的语言一样,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*3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'spam' is not defined
>>> '2' + 2
Traceback (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 sys

try:
    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

tryexcept语句有一个可选的 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 = spam
y = 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 func
OSError

The 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 None

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
RuntimeError

自定义异样

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

class Error(Exception):
    """Base class for exceptions in this module."""
    pass

class 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 = message

class 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!
KeyboardInterrupt
Traceback (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/

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

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

退出移动版