错误和异常 - QLGQ/learning-python GitHub Wiki

错误

  • 语法错误:语法错误指示软件的结构上有错误,导致不能被解释器解释或编译器无法编译。这些错误必须在程序执行前纠正。
  • 逻辑错误:当程序的语法正确后,剩下的就是逻辑错误了。逻辑错误可能是由于不完整或是不合法的输入所致;在其他情况下,还可能是逻辑无法生成、计算、或是输出结果需要的过程无法执行。这些错误通常分别被称为域错误和范围错误。

异常

对异常的最好描述是:它是因为程序出现了错误而在正常控制流以外釆取的行为。这个行为又分为两个阶段:首先是引起异常发生的错误,然后是检测(和釆取可能的措施)阶段。

Python中的异常

  1. NameError:尝试访问一个未申明的变量
foo
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'foo' is not defined
  1. ZeroDivisionError:除数为零
1/0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero
  1. SyntaxError:Python解释器语法错误
for
  File "<stdin>", line 1
    for
      ^
SyntaxError: invalid syntax

SyntaxError异常是唯一不是在运行时发生的异常。它代表Python代码中有一个不正确的结构,在它改正之前程序无法执行。这些错误一般都是在编译时发生,Python解释器无法把你的脚本转化为Python字节代码。当然这也可能是你导入一个有缺陷的模块的时候。

  1. IndexError:请求的索引超出序列范围
aList = []
aList[0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range
  1. KeyError:请求一个不存在的字典关键字
aDict = {'host': 'earth', 'port': 80}
print aDict['server']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'server'
  1. IOError:输入/输出错误
f = open("blash")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IOError: [Errno 2] No such file or directory: 'blash'

类似尝试打开一个不存在的磁盘文件一类的操作会引发一个操作系统输入/输出(I/O)错误。任何类型的I/O错误都会引发IOError异常。

  1. AttributeError:尝试访问未知的对象属性
class myClass(object):
    pass
myInst = myClass()
myInst.bar = 'spam'
myInst.bar
'spam'
myInst.foo
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'myClass' object has no attribute 'foo'
  1. TypeError:参数类型不正确
float(['this is', 1, 'list'])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: float() argument must be a string or a number

float()内建函数的基本作用是把任意一个数值类型转换为一个浮点型。从Python1.5开始,float()增加了把字符串表示的数值转换为浮点型的功能。

  1. ValueError:参数值不正确
float('foo')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: could not convert string to float: foo

检测和异常处理

忽略代码,继续执行和向上移交
try语句块中异常发生点后的剩余语句永远不会到达(所以永远不会执行)。一旦一个异常被引发,就必须决定控制流下一步到达的位置。剩余代码将被忽略,解释器将搜索处理器,一旦找到,就开始执行处理器中的代码。

如果没有找到合适的处理器,那么异常就向上移交给调用者去处理,这意味着堆栈框架立即回到之前的那个。如果在上层调用者也没找到对应处理器,该异常会继续被向上移交,直到找到合适处理器。如果到达顶层仍然没有找到对应处理器,那么就认为这个异常是未处理的,Python解释器会显示出跟踪记录,然后退出。

当函数没有显示地返回一个值时,例如没有执行return object语句函数就结束了,它就会返回None。但是在交互式环境下,不会显示出来,也即运行脚本时才会显示出来。

try-except语句

try-except语句语法如下:

try:
    try_suite    # 监控这里的异常
except Exception[, reason]:
    except_suite    # 异常处理代码

处理多个异常的except语句

我们可以在一个except子句里处理多个异常,except语句在处理多个异常时要求异常被放在一个元组里:

except (Exception1, Exception2) [, reason]:
    suite_for_Exception1_and_Exception2

else子句

在try范围中没有异常被检测到时,执行else子句。在else范围中的任何代码运行前,try范围中的所有代码必须完全成功(也就是,结束前没有引发异常)。

下面是用Python伪代码写的简短例子。

import 3rd_party_module
log = open('logfile.txt', 'w')
try:
    3rd_party_module.function()
except:
    log.write("*** caught exception in module\n")
else:
    log.write("*** no exceptions caugh\n")
log.close()

try-except-else-finally

try:
    try_suite
except Exception1:
    suite_for_Exception1
except (Exception2, Exception3, Exception4):
    suite_for_Exception_2_3_and_4
except Exception5, Argument5:
    suite_for_Exception5_plus_argument
except (Exception6, Exception7), Argument67:
    suite_for_Exception6_and_7_plus_argument
except:
    suite_for_all_other_exceptions
else:
    no_exceptions_detected_suite
finally:
    always_execute_suite

触发异常

raise语句

raise一般的用法是:

raise [SomeException [, args [, traceback]]]
  • 第一个参数,SomeException,是触发异常的名字。如果有,它必须是一个字符串,类或实例。如果有其他参数(arg或traceback),就必须提供SomeException。
  • 第二个符号为可选的args(比如参数,值)来传给异常。这可以是一个单独的对象也可以是一个对象的元组。当异常发生时,异常的参数总是作为一个元组传入。
  • 最后一项参数,traceback,同样是可选的(实际上很少用它)。如果有的话,则是当异常触发时新生成的一个用于异常-正常化(exception-normally)的跟踪记录(traceback)对象。当你想重新引发异常时,第三个参数很有用(可以用来区分先前和当前的位置)。如果没有这个参数,就填写None。

断言

断言是一句必须等价于布尔真的判定;此外,发生异常也意味着表达式为假。
断言可以简简单单的想象为raise-if语句(更准确的说是raise-if-not语句)。测试一个表达式,如果返回值是假,触发异常。
断言通过assert语句实现,断言语句等价于这样的Python表达式,如果断言成功不采取任何措施(类似语句),否则触发AssertionError(断言错误)的异常。assert的语法如下:

assert expression[, arguments]

AssertionError异常和其他的异常一样可以用try-except语句快捕捉,但是如果没有捕捉,它将终止程序运行而且提供一个如下的跟踪记录:

assert 1 == 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

assert 1 == 0, 'one does not equal zero silly!'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError: one does not equal zero silly!

try:
    assert 1 == 0, 'One does not equal zero silly!'
except AssertionError, args:
    print '%s: %s' % (args.__class__.__name__, args)
AssertionError: One does not equal zero silly!

为了让你更加了解assert如何运作,想象一下断言语句在Python中如何用函数实现。可以像下面这样:

def assert(expr, args=None):
    if __debug__ and not expr:
        raise AssertionError, args

标准异常

Python内建异常

异常名称 描述
BaseException 所有异常的基类
SystemExit python解释器请求退出
KeyboardInterrupt 用户中断执行(通常是输入^C)
Exception 常规错误的基类
StopIteration 迭代器没有更多的值
GeneratorExit 生成器(generator)发生异常来通知退出
StandardError 所有的内建标准异常的基类
ArithmeticError 所有数值计算错误的基类
FloatingPointError 浮点计算错误
OverflowError 数值运算超出最大限制
ZeroDivisionError 除(或取模)零(所有数据类型)
AssertionError 断言语句失败
AttributeError 对象没有这个属性
EOFError 没有内建输入,到达EOF标记
EnvironmentError 操作系统错误的基类
IOError 输入/输出操作失败
OSError 操作系统错误
WindowsError Windows系统调用失败
ImportError 导入模块/对象失败
LookupError 无效数据查询的基类
IndexError 序列中没有此索引(index)
KeyError 映射中没有这个键
MemoryError 内存溢出错误(对于Python解释器不是致命的)
NameError 未声明/初始化对象(没有属性)
UnboundLocalError 访问未初始化的本地变量
ReferenceError 弱引用(weak reference)试图访问已经垃圾回收了的对象
RuntimeError 一般的运行时错误
NotImplementedError 尚未实现的方法
SyntaxError Python语法错误
IndentationError 缩进错误
TabError Tab和空格混用
SystemError 一般的解释器系统错误
TypeError 对类型无效的操作
ValueError 传入无效的参数
UnicodeError Unicode相关的错误
UnicodeDecodeError Unicode解码时的错误
UnicodeEncodeError Unicode编码时的错误
UnicodeTranslateError Unicode转换时错误
Warning 警告的基类
DeprecationWarning 关于被弃用的特征的警告
FutureWarning 关于构造将来语义会有改变的警告
OverflowWarning 旧的关于自动提升为长整型(long)的警告
PendingDeprecationWarning 关于特性将会被废弃的警告
RuntimeWarning 可疑的运行时行为(runtime behavior)的警告
SyntaxWarning 可疑的语法的警告
UserWarning 用户代码生成的警告

所有的标准/内建异常都是从根异常派生的。目前有3个直接从BaseException派生的异常子类:SystemExit,KeyboardInterrupt和Exception。其他的所有的内建异常都是Exception的子类。

⚠️ **GitHub.com Fallback** ⚠️