python中至少包括两种错误:语法错误(syntax errors)和异常(exceptions)。
1.语法错误
语法错误,也被称作解析错误
语法分析器指出错误行,并且在检测到错误的位置前面显示一个小“箭头”。 错误是由箭头前面的标记引起的(或者至少是这么检测的)。错误会输出文件名和行号,所以如果是从脚本输入的你就知道去哪里检查错误了。
2.异常
即使一条语句或表达式在语法上是正确的,当试图执行它时也可能会引发错误。 运行期检测到的错误称为异常。此时会停止代码的执行,而大多数异常是并没有被处理的,所以会得到这样的异常信息显示:
打印错误信息时,异常的类型作为异常的内置名显示。对于所有的内置异常都是如此,不过用户自定义异常就不一定了(尽管这是一个很有用的约定)。标准异常名是内置的标识(没有保留关键字)。
python的标准异常有以下这些:
异常名称 | 描述 |
BaseException | 所有异常的基类 |
SystemExit | 解释器请求退出 |
KeyboardInterrupt | 用户中断执行(通常是输入ctrl+c) |
Exception | 常规错误的基类 |
StopIteration | 迭代器没有更多的值 |
GeneratorExit | 生成器(generator)发生异常来通知退出 |
StandardError | 所有的内建标准异常的基类 |
ArithmeticError | 所有数值计算错误的基类 |
FloatingPointError | 浮点计算错误 |
OverflowError | 数值运算超出最大限制 |
ZeroDivisionError | 除(或取模)零 (所有数据类型) |
AssertionError | 断言语句失败 |
AttributeError | 对象没有这个属性 |
EOFError | 没有内建输入,到达EOF 标记 |
EnvironmentError | 操作系统错误的基类 |
IOError | 输入/输出操作失败 |
OSError | 操作系统错误 |
WindowsError | 系统调用失败 |
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.异常处理
我们可以使用 try/except 语句来捕捉并处理异常。
try/except语句用来检测try语句块中的错误,从而让except语句捕获异常信息并处理。
如果你不想在异常发生时结束你的程序,只需在try里捕获它。
try 语句的执行顺序:
1.首先,执行 try 子句 (在 try 和 except 关键字之间的部分)。
2.如果没有异常发生, except 子句 在 try 语句执行完毕后就被忽略了。
3.如果在 try 子句执行过程中发生了异常,那么该子句其余的部分就会被忽略。如果异常匹配于 except 关键字后面指定的异常类型,就执行对应的 except 子句。然后继续执行 try 语句之后的代码。
4.如果发生了一个异常,在 except 子句中没有与之匹配的分支,它就会传递到上一级 try 语句中。如果最终仍找不到对应的处理语句,它就成为一个未处理异常,终止程序运行,显示提示信息。
while True: try: num = int(raw_input('请输入一个数字:')) print num break except ValueError: print '非法字符' print '我在try之后'
示例中,当我输入一个无法被转换为数字的 @ 号时,本来应该触发ValueError异常的。但是进行了异常处理了之后,当我输入 @ 号时,异常被捕捉到了,同时执行了except中的语句,并执行了try之后的代码。但因为是在永真的while循环中,所以又执行了一遍,这时我输入了正确的数字,所以try中的语句能继续执行下去,又遇到了break,循环退出。
一个 try 语句可能包含多个 except 子句(至少一个),分别指定处理不同的异常。至多只会有一个分支被执行。
try: '''尝试各种操作'''
except IOError as e: '''捕捉到这种异常,就执行这里的代码'''
except ValueError: '''捕捉到这种异常,就执行这里的代码''' except: '''如果发生的异常不是上面的两种,那么剩下的异常都统一这样处理'''
最后一个 except 子句可以省略异常名称,以作为通配符使用。但是正以为它能捕捉任何的异常,所以一些在意料之外的异常也会被掩盖掉。
我们也可以用一个except 子句捕捉多个异常,做统一的处理:
except (RuntimeError, TypeError, NameError): pass
这时又有同学好奇 except IOError as e: 是什么意思,下面看代码演示:
while True: try: num = int(raw_input('请输入一个数字:')) print num break except ValueError as msg: #等价于:except ValueError,msg: print msg
发现是报错信息,和不做异常处理的下面的一样:
看看其类型是什么:
print type(msg)
看看里面有什么方法:
print dir(msg)
非常多,一行显示不完,不过多数是私有方法,我们重点关注后面的args,和message。
print msg.args print type(msg.args)
看来是将错误信息转换成字符串后保存到元祖中。
print msg.message print type(msg.message)
看来就是把错误信息转换成字符串。
try 除了可以配合 except使用之外,还能配合 else 和 finally 使用。
else子句只能出现在所有 except 子句之后。当 try 语句没有抛出异常时,需要执行一些代码,可以使用这个子句。
不管有没有发生异常, finally子句在程序离开 try 后都一定会被执行。当 try 语句中发生了未被 except 捕获的异常(或者它发生在 except 或 else 子句中),在 finally 子句执行完后它会被重新抛出。 try 语句经由 break ,continue 或 return 语句退出也一样会执行 finally 子句。
while True: try: num = int(raw_input('请输入一个数字:')) print num except ValueError, msg: print msg.message else: print '没有异常的时候才会触发' #当try中使用break ,continue 或 return 语句退出时,不执行 finally: print '无论如何我都会执行'
4.手动触发异常:
raise 语句允许程序员强制抛出一个指定的异常。
要抛出的异常由 raise 的唯一参数标识。它必需是一个异常实例或异常类(继承自 Exception 的类)。
如果你需要明确一个异常是否抛出,但不想处理它, raise 语句可以让你很简单的重新抛出该异常:
5.用户自定义异常
在程序中可以通过创建新的异常类型来命名自己的异常(Python 类的内容请参见类)。异常类通常应该直接或间接的从 Exception 类派生,例如:
class MyError(Exception): def __init__(self, value): self.value = value def __str__(self): return repr(self.value) try: raise MyError('错误信息') except MyError as msg: print msg.value print msg.args print '-----', msg.message
Exception 默认的 __init__() 被覆盖。新的方式简单的创建 value 属性。这就替换了原来创建 args 属性的方式。
6. assert 断言
assert是用来检查一个条件,如果它为真,就不做任何事。如果它为假,则会抛出AssertError并且包含错误信息。
格式: assert expression [, arguments] (expression:表达式,arguments:参数,多是字符串来说明错误)
a = 1 assert a < 5 assert a > 5, '根本没有这会事'
当然我们也可以捕获它。
a = 1 try: assert a > 5, '根本没有这回事' except AssertionError as msg: print msg.args print msg.message
为什么要处理异常?
因为这样更保险,你不能保证所有代码都是对的,而又不想因为某处的小错误而让这个程序都无法执行,这样代价太大。所有说凡事try一下,没有什么坏处的。
关于异常暂时就说到这里,有错误或不足的地方以后会进行修改。欢迎积极留言讨论。