Python使用异常对象来表示异常状态,并在遇到错误时引发异常。
raise语句可以引发异常,将一个类或实例作为参数。
>>> raise Exception #引发的是通用异常,没有指出是什么错误 Traceback (most recent call last): File "<pyshell#120>", line 1, in <module> raise Exception Exception >>> >>> raise Exception('hyperdrive overload') #添加了错误消息yperdrive overload Traceback (most recent call last): File "<pyshell#125>", line 1, in <module> raise Exception('hyperdrive overload') Exception: hyperdrive overload
一些内置的异常类
类名 | 描述 |
Exception | 几乎所有的异常类都是从它派生而来的 |
AttributeError | 引用属性或给它赋值失败时引发 |
OSError | 操作系统不能执行指定的任务(如打开文件)时引发,有多个子类 |
IndexError | 使用序列中不存在的索引时引发,为LookupError的子类 |
KeyError | 使用映射中不存在的键时引发,为LookupError的子类 |
NameError | 找不到名称(变量)时引发 |
SyntaxError | 代码不正确时引发 |
TypeError | 将内置操作或函数用于类型不正确的对象时引发 |
ValueError | 将内置操作或函数用于这样的对象时引发:其类型正确但包含的值不合适 |
ZeroDivisionError | 在除法或求模运算的第二个参数为零时引发 |
捕获异常后,如果重新引发它(继续向上传播),可调用raise且不提供任何参数。
>>> class MuffledCalculator: muffled = False #关闭“抑制”功能,引发异常 def calc(self,expr): try: return eval(expr) except ZeroDivisionError: if self.muffled: print('Division by zero is illegal') else: raise >>> calculator = MuffledCalculator() >>> calculator.calc('10/2') 5.0 >>> calculator.calc('10/0') #捕获异常ZeroDivisionError后,继续向上传播它 Traceback (most recent call last): File "<pyshell#17>", line 1, in <module> calculator.calc('10/0') File "<pyshell#14>", line 5, in calc return eval(expr) File "<string>", line 1, in <module> ZeroDivisionError: division by zero >>> calculator.muffled = True #打开“抑制”功能,打印一条错误信息,不让异常继续传播 >>> calculator.calc('10/0') Division by zero is illegal
eval函数:将字符串str当成有效的表达式来求值并返回计算结果。
可使用raise...from...语句来提供自己的异常上下文,也可使用None来禁用上下文。
>>> try: 1/0 except ZeroDivisionError: raise ValueError from None Traceback (most recent call last): File "<pyshell#28>", line 4, in <module> raise ValueError from None ValueError
一个except子句捕获多种异常,可在一个元组中指定这些异常:
>>> try: x= int(input('enter 1:')) y= int(input('enter 2:')) print(x/y) except(ZeroDivisionError,TypeError,NameError): print('.......') enter 1:1 enter 2:0 .......
合理使用else子句:
>>> while True: try: x = int(input('enter your first number:')) y = int(input('enter your second number:')) value = x/y print('x / y is ',value) except: print('Invalid input.Plase try again') else: break enter your first number:10 enter your second number:0 Invalid input.Plase try again enter your first number:2 enter your second number:m Invalid input.Plase try again enter your first number:5 enter your second number:'9' Invalid input.Plase try again enter your first number:10 enter your second number:2 x / y is 5.0
当没有引发异常时,才会跳出循环。如果出现错误,程序会要求用户提供新的输入。
>>> while True: try: x = int(input('enter your first name:')) y = int(input('enter your second name:')) value = x/y print('x/y is ',value) except Exception as e: print('Invalid input:',e) print('Plase try agagin') else: break enter your first name:10 enter your second name:0 Invalid input: division by zero Plase try agagin enter your first name:10 enter your second name:p Invalid input: invalid literal for int() with base 10: 'p' Plase try agagin enter your first name:'10' Invalid input: invalid literal for int() with base 10: "'10'" Plase try agagin enter your first name:10 enter your second name:2 x/y is 5.0
使用except Exception as e可以在程序中打印更有用的错误消息。
finally子句,可用于在发生异常时执行清理工作。与try子句配套使用.
>>> try: 1/0 except NameError: print('Unknown variable') else: print('That went well!') finally: print('Cleaning up.') Cleaning up. Traceback (most recent call last): File "<pyshell#89>", line 2, in <module> 1/0 ZeroDivisionError: division by zero
栗子:假设有一个字典,你要在指定的键存在时打印与之相关联的值,否则什么都不做。
>>> def describe_person(person): print('Description of',person['name']) print('age:',person['age']) if 'occupation' in person: print('Occupation:',person['occupation']) >>> p = dict(name='Throatwobbler Mangrove',age=25) >>> describe_person(p) Description of Throatwobbler Mangrove age: 25
这段代码很直观,但它必须两次查找'occupation'键:1次检查这个键是否存在(条件中),另一次获取这个键的值,打印。
优化一下:
>>> def describe_person(person): print('Description of',person['name']) print('age:',person['age']) try: print('Occupation:',person['occupation']) #函数直接假设存在'occupation',如果假设成立,直接获取并打印值,不用检查键是否存在。 except KeyError:pass >>> p = dict(name='Throatwobbler Mangrove',age=25) >>> describe_person(p) Description of Throatwobbler Mangrove age: 25
>>> while True:
try:
x = int(input('enter your first name:'))
y = int(input('enter your second name:'))
value = x/y
print('x/y is ',value)
except Exception as e:
print('Invalid input:',e)
print('Plase try agagin')
else:
break
enter your first name:10
enter your second name:0
Invalid input: division by zero
Plase try agagin
enter your first name:10
enter your second name:p
Invalid input: invalid literal for int() with base 10: 'p'
Plase try agagin
enter your first name:'10'
Invalid input: invalid literal for int() with base 10: "'10'"
Plase try agagin
enter your first name:10
enter your second name:2
x/y is 5.0