至少有两种错误:语法错误和异常。
语法错误
语法错误又叫解析错误:
>>> while True print 'Hello world'
File "", line 1, in ?
while True print 'Hello world'
^
SyntaxError: invalid syntax
分析器指出错误行,并显示"
"在出错的地方。脚本执行时还会显示文件名和对应的行号,这里错误是print前面没有分号。
异常
即便语句或表达式语法正确,执行时也可能报错。运行时错误称为异常,它不会无条件的崩溃,通常是程序没有处理好:
>>> 10 * (1/0)
Traceback (most recent call last):
File "", line 1, in ?
ZeroDivisionError: integer division or modulo by zero
>>> 4 + spam*3
Traceback (most recent call last):
File "", line 1, in ?
NameError: name 'spam' is not defined
>>> '2' + 2
Traceback (most recent call last):
File "", line 1, in ?
TypeError: cannot concatenate 'str' and 'int' objects
ZeroDivisionError? , NameError和TypeError是异常类型,即异常的内置名,内置异常约定如此,建议自定义的异常也如此。标准异常名是内置的标识(但不是保留关键字)。异常名所在行的后续部分是异常类型的详细说明和产生原因。余下部分显示上下文,通常是堆栈traceback形式。通常列出了源代码行,但不会显示标准输入。
异常处理
下例一直要求用户输入,直到输入合法的整数,但允许用户中断(使用Control-C等)。 注意用户中断会产生KeyboardInterrupt异常。
>>> while True:
... try:
... x = int(raw_input("Please enter a number: "))
... break
... except ValueError:
... print "Oops! That was no valid number. Try again..."
...
try 语句按如下方式工作:
首先,执行try和except关键字之间的部分。
如果没有异常发生, except后面的部分不会执行。
如果有异常发生,停止执行后续语句,跳转到指定的异常处理部分。
如果异常没有处理,会传到外层的try,如果最终没有处理,如报出异常。
try语句可能包含多个except子句,分别处理不同的异常,只有一个分支执行。一个except同时处理多个异常,例如:
import sys
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except IOError as e:
print "I/O error({0}): {1}".format(e.errno, e.strerror)
except ValueError:
print "Could not convert data to an integer."
except:
print "Unexpected error:", sys.exc_info()[0]
raise
try ... except以带一个 else子句,用于无异常时的执行。例如
import sys
for arg in sys.argv[1:]:
try:
f = open(arg, 'r')
except IOError:
print 'cannot open', arg
else:
print arg, 'has', len(f.readlines()), 'lines'
f.close()
使用else子句比在 try 子句中附加代码要好,因为这样可以避免try ... except截获不相关的异常。
异常时可能有相关值,即异常的参数,它和具体异常有关。
可以为 except子句指定变量,该变量绑定了异常实例及其参数中。异常实例定义了 str ()绑定了相关参数instance.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 printed directly
... x, y = inst.args
... print 'x =', x
... print 'y =', y
...
('spam', 'eggs')
('spam', 'eggs')
x = spam
y = eggs
如果异常有参数,在异常未处理的时候会在最后面打印出来。
函数中的异常也会处理。
>>> def this_fails():
... x = 1/0
...
>>> try:
... this_fails()
... except ZeroDivisionError as detail:
... print 'Handling run-time error:', detail
...
Handling run-time error: integer division or modulo by zero
抛出异常
raise语句强行产生指定的异常。例如:
>>> raise NameError('HiThere')
Traceback (most recent call last):
File "", line 1, in ?
NameError: HiThere
raise后面要接异常实例或异常类(继承自Exception类)。
简单一句raise可以重新最近的异常,但是因为不清晰不建议使用:
>>> try:
... raise NameError('HiThere')
... except NameError:
... print 'An exception flew by!'
... raise
...
An exception flew by!
Traceback (most recent call last):
File "", line 2, in ?
NameError: HiThere
用户异常
继承Exception可以创建新异常:
>>> class MyError(Exception):
... def __init__(self, value):
... self.value = value
... def __str__(self):
... return repr(self.value)
...
>>> try:
... raise MyError(2*2)
... except MyError as e:
... print 'My exception occurred, value:', e.value
...
My exception occurred, value: 4
>>> raise MyError('oops!')
Traceback (most recent call last):
File "", line 1, in ?
__main__.MyError: 'oops!'
该例重载了Exception默认的 init (),用value替换了args。
异常类中可以定义其他东西,但是通常建议简介,只加入属性信息,以供异常处理句柄提取。如果需要抛出几种不同的错误时,建议由异常基类和对应的异常子类:
class Error(Exception):
"""Base class for exceptions in this module."""
pass
class InputError(Error):
"""Exception raised for errors in the input.
Attributes:
expr -- input expression in which the error occurred
msg -- explanation of the error
"""
def __init__(self, expr, msg):
self.expr = expr
self.msg = msg
class TransitionError(Error):
"""Raised when an operation attempts a state transition that's not
allowed.
Attributes:
prev -- state at beginning of transition
next -- attempted new state
msg -- explanation of why the specific transition is not allowed
"""
def __init__(self, prev, next, msg):
self.prev = prev
self.next = next
self.msg = msg
大多数异常的命名都以 “Error” 结尾。
很多标准模块中都定义了自己的异常以方便报告错误。
finally
finally子句中的内容无论是否发生异常都会执行。
>>> try:
... raise KeyboardInterrupt
... finally:
... print 'Goodbye, world!'
...
Goodbye, world!
KeyboardInterrupt
无论如何都要执行finally才能退出, 多用于释放资源:
... try:
... result = x / y
... except ZeroDivisionError:
... print "division by zero!"
... else:
... print "result is", result
... finally:
... print "executing finally clause"
...
>>> divide(2, 1)
result is 2
executing finally clause
>>> divide(2, 0)
division by zero!
executing finally clause
>>> divide("2", "1")
executing finally clause
Traceback (most recent call last):
File "", line 1, in ?
File "", line 3, in divide
TypeError: unsupported operand type(s) for /: 'str' and 'str'
预定义清理
有些对象定义了标准的清理行为,无论是否成功,不需要该对象的时会起作用。下例打开文件并把内容打印到屏幕上:
for line in open("myfile.txt"):
print line,
这段代码的问题在于执行完毕后没有关闭文件,在大型应用程序就会出问题。 with语句可以确认相关资源及时释放:
with open("myfile.txt") as f:
for line in f:
print line,
本文地址