`
v5qqcom
  • 浏览: 1285596 次
文章分类
社区版块
存档分类
最新评论

Python指南--错误和异常

 
阅读更多

子目录

<!--End of Table of Child-Links-->


8. 错误和异常

至今为止还没有进一步的谈论过错误信息,不过在你已经试验过的那些例子中,可能已经遇到过一些。Python中(至少)有两种错误:语法错误和异常( syntax errors and exceptions)。


8.1 语法错误

语法错误,也称作解析错误,可能是学习Python的过程中最容易犯的:

>>> while True print 'Hello world'
  File "<stdin>", line 1, in ?</stdin>
    while True print 'Hello world'
                   ^
SyntaxError: invalid syntax

解析器会重复出错的行,并在行中最早发现的错误位置上显示一个小箭头。错误(至少是被检测到)就发生在箭头指向的位置。示例中的错误表现在关键字print上,因为在它之前少了一个冒号(:)。同时也会显示文件名和行号,这样你就可以知道错误来自哪个脚本,什么位置。


8.2 异常

即使是在语法上完全正确的语句,尝试执行它的时候,也有可能会发生错误。在程序运行中检测出的错误称之为异常,它通常不会导致致命的问题,你很快就会学到如何在Python程序中控制它们。大多数异常不会由程序处理,而是显示一个错误信息:

>>> 10 * (1/0)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?</stdin>
ZeroDivisionError: integer division or modulo by zero
>>> 4 + spam*3
Traceback (most recent call last):
  File "<stdin>", line 1, in ?</stdin>
NameError: name 'spam' is not defined
>>> '2' + 2
Traceback (most recent call last):
  File "<stdin>", line 1, in ?</stdin>
TypeError: cannot concatenate 'str' and 'int' objects

错误信息的最后一行指出发生了什么错误。异常也有不同的类型,异常类型做为错误信息的一部分显示出来:示例中的异常分别为零除错误( ZeroDivisionError ),命名错误( NameError)和类型错误( TypeError )。打印错误信息时,异常的类型作为异常的内置名显示。对于所有的内置异常都是如此,不过用户自定义异常就不一定了(尽管这是一个很有用的约定)。标准异常名是内置的标识(没有保留关键字)。

这一行后一部分是关于该异常类型的详细说明,这意味着它的内容依赖于异常类型。

错误信息的前半部分以堆栈的形式列出异常发生的位置。通常在堆栈中列出了源代码行,然而,来自标准输入的源码不会显示出来。

Python 库参考手册 列出了内置异常和它们的含义。


8.3 处理异常

通过编程可以处理指定的异常。以下的例子重复要求用户输入一个值,直到用户输入的是一个合法的整数为止。不过这个程序允许用户中断程序(使用 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 子句(在try except关键字之间的部分)。

  • 如果没有异常发生,except 子句try语句执行完毕后就被忽略了。

  • 如果在try子句执行过程中发生了异常,那么该子句其余的部分就会被忽略。如果异常匹配于except关键字后面指定的异常类型,就执行对应的except子句,忽略try子句的其它部分。然后继续执行try语句之后的代码。

  • 如果发生了一个异常,在except子句中没有与之匹配的分支,它就会传递到上一级try语句中。如果最终仍找不到对应的处理语句,它就成为一个未处理异常,终止程序运行,显示提示信息。

一个try 语句可能包含多个 except 子句,分别指定处理不同的异常。至多只会有一个分支被执行。异常处理程序只会处理对应的try子句中发生的异常,在同一个try语句中,其他子句中发生的异常则不作处理。一个except子句可以在括号中列出多个异常的名字,例如:

... except (RuntimeError, TypeError, NameError):
...     pass

最后一个except子句可以省略异常名,把它当做一个通配项使用。一定要慎用这种方法,因为它很可能会屏蔽掉真正的程序错误,使人无法发现!它也可以用于打印一行错误信息,然后重新抛出异常(可以使调用者更好的处理异常)。

import string, sys

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(string.strip(s))
except IOError, (errno, strerror):
    print "I/O error(%s): %s" % (errno, strerror)
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 IOError:
        print 'cannot open', arg
    else:
        print arg, 'has', len(f.readlines()), 'lines'
        f.close()

使用 else 子句比在 try 子句中附加代码要好,因为这样可以避免 try ... except 意外的截获本来不属于它们保护的那些代码抛出的异常。

发生异常时,可能会有一个附属值,作为异常的参数存在。这个参数是否存在、是什么类型,依赖于异常的类型。

在异常名(列表)之后,也可以为 except 子句指定一个变量。这个变量绑定于一个异常实例,它存储在 instance.args 的参数中。为了方便起见,异常实例定义了 __getitem____str__ ,这样就可以直接访问过打印参数而不必引用 .args

>>> try:
...    raise Exception('spam', 'eggs')
... except Exception, 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          # __getitem__ allows args to be unpacked directly
...    print 'x =', x
...    print 'y =', y
...
<type></type>
('spam', 'eggs')
('spam', 'eggs')
x = spam
y = eggs

对于未处理的异常,如果它有一个参数,那做就会作为错误信息的最后一部分(“明细”)打印出来。

异常处理句柄不止可以处理直接发生在try子句中的异常,即使是其中(甚至是间接)调用的函数,发生了异常,也一样可以处理。例如:

>>> def this_fails():
...     x = 1/0
... 
>>> try:
...     this_fails()
... except ZeroDivisionError, detail:
...     print 'Handling run-time error:', detail
... 
Handling run-time error: integer division or modulo


8.4 抛出异常

在发生了特定的异常时,程序员可以用 raise 语句强制抛出异常。例如:

>>> raise NameError, 'HiThere'
Traceback (most recent call last):
  File "<stdin>", line 1, in ?</stdin>
NameError: HiThere

第一个参数指定了所抛出异常的名称,第二个指定了异常的参数。

如果你决定抛出一个异常而不处理它,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 ?</stdin>
NameError: HiThere


8.5 用户自定义异常

在程序中可以通过创建新的异常类型来命名自己的异常。异常类通常应该直接或间接的从 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, e:
...     print 'My exception occurred, value:', e.value
... 
My exception occurred, value: 4
>>> raise MyError, 'oops!'
Traceback (most recent call last):
  File "<stdin>", line 1, in ?</stdin>
__main__.MyError: 'oops!'

异常类中可以定义任何其它类中可以定义的东西,但是通常为了保持简单,只在其中加入几个属性信息,以供异常处理句柄提取。如果一个新创建的模块中需要抛出几种不同的错误时,一个通常的作法是为该模块定义一个异常基类,然后针对不同的错误类型派生出对应的异常子类。

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

与标准异常相似,大多数异常的命名都以“Error”结尾。

很多标准模块中都定义了自己的异常,用以报告在他们所定义的函数中可能发生的错误。关于类的进一步信息请参见第 9章,“类”。


8.6 定义清理行为

try 语句还有另一个可选的子句,目的在于定义在任何情况下都一定要执行的功能。例如:

>>> try:
...     raise KeyboardInterrupt
... finally:
...     print 'Goodbye, world!'
... 
Goodbye, world!
Traceback (most recent call last):
  File "<stdin>", line 2, in ?</stdin>
KeyboardInterrupt

不管try子句中有没有发生异常, finally 子句都一定会被执行。如果发生异常,finally子句执行完后它会被重新抛出。 try 子句经由 break return 退出也一样会执行finally 子句。

在finally 子句中的代码用于释放外部资源(例如文件或网络连接),不管这些资源是否已经成功利用。

try 语句中可以使用若干个 except 子句或一个 finally 子句,但两者不能共存。


分享到:
评论

相关推荐

    Python3.4.3 入门指南-111410151

    1. 开胃菜 4. 深入 Python 流程控制 5. 数据结构 6. 模块 7. 输入和输出 8. 错误和异常 9. 类 1. 开胃菜 1. 开胃菜 1. 开

    Python Tutorial Python入门指南

    python教程,对python的用途以及python的概念作了介绍,并按照流程控制、数据结构、Modules,错误和异常以及class做了详细的描述

    新版Python官方入门指南中文版

    本手册不会尝试涵盖Python的全部知识和每个特性,甚至不会涵盖所有常用的特性...8.Python错误与异常 9.Python类 10.Python标准库概览 11.Python标准库概览第二部分 12.现在做什么呢 13.Python交互的输入编辑和历史记录

    python-rest-sample

    输入验证和异常处理 地理位置地址查找和坐标方法(不适用) 模型的单元测试 通过邮递员进行功能测试 用户指南以及数据和代码示例 去做 交互式“ /environment/build/docker.sh”脚本,用于将镜像推入/拉出/...

    python_3.4官方入门指南中文版

    该文档是基于Python3.4的入门教程,简单介绍了Python(数据、字符串、列表等),流程控制(if,for,break等),数据结构(元组、序列、集合、字典),相关模块,输入输出控制格式,错误异常处理,类的描述、标准库...

    python 3.1入门指南.pdf

    本手册指南向读者介绍了Python语言及其相关的基本知识与概念,由外文翻译成中文的版本。包括使用Python解释器、数据结构、错误和异常、Python标准库概览等等。

    Python 核心编程 第二版

    第1部分占据了大约三分之二的篇幅,阐释这门语言的“核心”内容,包括基本的概念和语句、语法和风格、 Python对象、数字类型、序列类型、映射和集合类型、条件和循环、文件和输入/输出、错误和异常、函数和函数式...

    2024最强Python春招面试题(一篇就够了).zip这篇博客为即将参加春招的Python初学者提供了一个全面的面试准备指南

    通过深入解析Python面试中常见的题目,如Python基础、函数和模块、面向对象编程、错误和异常处理、数据结构和算法、Python库和框架等,本博客旨在帮助求职者更好地准备Python相关的职位面试。 适用人群: 本博客主要...

    Python异常对代码运行性能的影响实例解析

    Python异常(谷歌开源风格指南) tip: 允许使用异常, 但必须小心。 定义: 异常是一种跳出代码块的正常控制流来处理错误或者其它异常条件的方式。 优点: 正常操作代码的控制流不会和错误处理代码混在一起. 当某种...

    Python核心编程第二版(ok)

     2.16 错误和异常   2.17 函数   2.17.1 如何定义函数   2.17.2 如何调用函数   2.17.3 默认参数   2.18 类   2.19 模块   2.19.1 如何导入模块   2.19.2 如何访问一个模块函数或访问一个...

    Python核心编程第二版

     2.16 错误和异常   2.17 函数   2.17.1 如何定义函数   2.17.2 如何调用函数   2.17.3 默认参数   2.18 类   2.19 模块   2.19.1 如何导入模块   2.19.2 如何访问一个模块函数或访问一个...

    The-Python-Workshop:一种新的交互式Python学习方法

    要求和设置 要开始使用项目文件,您需要: 在 , , 上安装Jupyter 在 , , 上安装Anaconda 安装Docker 关于Python工作坊“ Python研讨会”不仅为初学者提供Python指南,还为您提供了从基础到高级主题的全部内容,...

    python 核心编程 第二版

    第1部分占据了大约三分之二的篇幅,阐释这门语言的“核心”内容,包括基本的概念和语句、语法和风格、Python对象、数字类型、序列类型、映射和集合类型、条件和循环、文件和输入/输出、错误和异常、函数和函数式编程...

    Python核心编程(第二版).pdf (压缩包分2部分,第二部分)

     2.16 错误和异常   2.17 函数   2.17.1 如何定义函数   2.17.2 如何调用函数   2.17.3 默认参数   2.18 类   2.19 模块   2.19.1 如何导入模块   2.19.2 如何访问一个模块函数或访问一个...

    Python Tutorial 新手入门教程 PDF版.rar

    Python Tutorial ——Python新手入门指南 PDF版,内容包括:  Whetting Your Appetite 开胃菜  Using the Python Interpreter使用Python解释器 ... Errors and Exceptions错误和异常  标准库概览…………

    像计算机科学家一样思考Python(第2版).pdf

    这是一本实用的学习指南,适合没有Python编程经验的程序员阅读,也适合高中或大学的学生、Python爱好者及需要了解编程基础的人阅读。对于首次接触程序设计的人来说,是一本不可多得的佳作。 作者简介 · · · · ...

    计算机二级Python题库超详细总结

    内容涵盖了Python的基本概念、数据类型、控制结构、函数、模块和包、输入输出、错误和异常处理等核心知识点,以及备考策略、考试技巧和备考资源等实用信息。 **适用人群:** 本教程适合所有准备参加计算机二级Python...

    Python核心编程(第二版).pdf (压缩包分2部分,第一部分)

     2.16 错误和异常   2.17 函数   2.17.1 如何定义函数   2.17.2 如何调用函数   2.17.3 默认参数   2.18 类   2.19 模块   2.19.1 如何导入模块   2.19.2 如何访问一个模块函数或访问一个...

    100_page_python_intro:Python编程语言的简短入门指南

    本书是Python编程语言的简短入门指南。 这本书非常适合: 作为Python初学者研讨会的参考资料 如果您以前有其他编程语言的经验 如果您在阅读完Python基础知识,观看视频课程等之后想要补充资源, 该书还包括练习,...

    Python核心编程(第二版).part1.rar

    第1部分占据了大约三分之二的篇幅,阐释这门语言的“核心”内容,包括基本的概念和语句、语法和风格、Python对象、数字类型、序列类型、映射和集合类型、条件和循环、文件和输入/输出、错误和异常、函数和函数式编程...

Global site tag (gtag.js) - Google Analytics