简介
和其余的语言一样,Python中也有异样和谬误。在 Python 中,所有异样都是 BaseException
的类的实例。 明天咱们来具体看一下Python中的异样和对他们的解决形式。
Python中的内置异样类
Python中所有异样类都来自BaseException,它是所有内置异样的基类。
尽管它是所有异样类的基类,然而对于用户自定义的类来说,并不举荐间接继承BaseException,而是继承Exception.
先看下Python中异样类的构造关系:
<code class="shell">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
其中BaseException,Exception,ArithmeticError,BufferError,LookupError 次要被作为其余异样的基类。
语法错误
在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
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 = 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/
最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!
欢迎关注搞代码gaodaima网的公众号:「程序那些事」,懂技术,更懂你!