Python学习系列之错误和异常

【Python】错误和异常 在任何编程语言中,错误处理都是构建健壮、可靠应用程序的基石。Python 提供了一套强大而灵活的异常处理机制。但在深入这些机制之前,我们必须清晰地理解什么是错误,什么是异常,以及它们在Python世界中的具体含义和分类。虽然在日常交流中,“错误”和“异常”这两个词经常互换使用,但在编程的上下文中,特别是Python中,它们既有联系也有细微但重要的区别。语法错误,也称为解析错误 (Parsing Errors),是Python解释器在解析代码(即读取并理解你的代码结构)的阶段发现的问题。这些错误意味着你的代码 阅读详情
AI摘要

本文深入讲解Python中的异常处理机制,包括错误与异常的区别,异常的捕获与处理,如try/except/finally语句的使用,用户自定义异常,以及异常处理的高级应用。同时,文章对比了异常处理与断言的使用场景,提供了实用的编程指导。

一、错误和异常

Python 中(至少)有两种错误:语法错误和异常( syntax errors 和 exceptions )。

1.1 错误

(1)语法错误,也被称作解析错误,无法通过python解释器的语法检测,必须在程序执行前就改正。比如:

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

语法分析器指出错误行,并且在检测到错误的位置前面显示一个小“箭头”。 错误是由箭头 前面 的标记引起的(或者至少是这么检测的): 这个例子中,函数 print() 被发现存在错误,因为它前面少了一个冒号( ':' )。 错误会输出文件名和行号,所以如果是从脚本输入的你就知道去哪里检查错误了。

1.2 异常

什么是异常?

       异常即是一个事件,该事件会在程序执行过程中发生,影响了程序的正常执行。一般情况下,在Python无法正常处理程序时就会发生一个异常。异常是Python对象,表示一个错误。即使一条语句或表达式在语法上是正确的,当试图执行它时也可能会引发错误。运行期检测到的错误称为 异常,并且程序不会无条件的崩溃。所以我们需要异常的处理来解决这些问题。当Python脚本发生异常时我们需要捕获处理它,否则程序会终止执行。

       异常也有不同的类型,异常类型做为错误信息的一部分显示出来:零除错误( ZeroDivisionError ) ,命名错误( NameError) 和 类型错误( TypeError )。打印错误信息时,异常的类型作为异常的内置名显示。对于所有的内置异常都是如此,不过用户自定义异常就不一定了(尽管这是一个很有用的约定)。标准异常名是内置的标识(没有保留关键字)。后一部分是关于该异常类型的详细说明,这意味着它的内容依赖于异常类型。错误信息的前半部分以堆栈的形式列出异常发生的位置。通常在堆栈中列出了源代码行,然而,来自标准输入的源码不会显示出来。

python提供了两个非常重要的功能来处理python程序在运行中出现的异常和错误。你可以使用该功能来调试python程序。

  • 异常捕获和处理(try/except/finally语句块)
  • 断言(Assertions

如果异常对象并未被处理或捕捉,程序就会用所谓的回溯(traceback)终止执行。

python2.x捕获异常语法(只能py2):

try:
    ...some functions...
except Exception, e:
    print(e)


python3.x捕获异常语法(py2也可以,推荐使用,有兼容能力,性能更好):

try:
    ...some functions...
except Exception as e:
    print(e)

 

二、异常捕获和处理

2.1 try/except语句

捕获异常可以使用try/except语句。

try/except语句用来检测try语句块中的错误,从而让except语句捕获异常信息并处理。如果你不想在异常发生时结束你的程序,只需在try里捕获它。

语法:

以下为简单的try....except...else的语法(可以有多个罗列的except子句,也可以在一个except中写多个捕获类型):

try:
<语句>        #运行别的代码
except <名字>:
<语句>        #如果在try部份引发了'name'异常
except <名字>,<数据>:
<语句>        #如果引发了'name'异常,获得附加的数据
else:
<语句>        #如果没有异常发生

try的工作原理是,当开始一个try语句后,python就在当前程序的上下文中作标记,这样当异常出现时就可以回到这里,try子句先执行,接下来会发生什么依赖于执行时是否出现异常。

else子句只能出现在所有 except 子句之后。当 try 语句没有抛出异常时,需要执行一些代码,可以使用这个子句。 

  • 如果当try后的语句执行时发生异常,python就跳回到try并执行第一个匹配该异常的except子句,异常处理完毕,控制流就通过了整个try语句(除非在处理异常时又引发新的异常)。
  • 如果在try后的语句里发生了异常,却没有匹配的except子句,异常将被递交到上层的try,或者到程序的最上层(这样将结束程序,并打印缺省的出错信息)。
  • 如果在try子句执行时没有发生异常,python将执行else语句后的语句(如果有else的话),然后控制流通过整个try语句。

示例:

try:
    fh = open("testfile", "w")
    fh.write("这是一个测试文件,用于测试异常!!")
except IOError:
    print "Error: 没有找到文件或读取文件失败"
else:
    print "内容写入文件成功"
    fh.close()
如果正常执行:
$ python test.py 
内容写入文件成功
$ cat testfile       # 查看写入的内容
这是一个测试文件,用于测试异常!!

如果写文件没有权限:
$ python test.py 
Error: 没有找到文件或读取文件失败

 (1)使用except而不带任何异常类型

你可以不带任何异常类型使用except,如下实例:

try:
    正常的操作
   ......................
except:
    发生异常,执行这块代码
   ......................
else:
    如果没有异常执行这块代码

以上方式try-except语句捕获所有发生的异常。但这不是一个很好的方式,我们不能通过该程序识别出具体的异常信息。因为它捕获所有的异常,除非不打印错误信息,只是为了捕获异常。

(2)使用except而带多种异常类型

一个 try 语句可能包含多个 except 子句,分别指定处理不同的异常。至多只会有一个分支被执行。异常处理程序只会处理对应的 try 子句中发生的异常,在同一个 try 语句中,其他子句中发生的异常则不作处理。一个except子句可以同时处理多个异常,这些异常将被放在一个括号里成为一个元组。一个 except 子句可以在括号中列出多个异常的名字,如下所示:

try:
    正常的操作
   ......................
except(Exception1[, Exception2[,...ExceptionN]]]):
   发生以上多个异常中的一个,执行这块代码
   ......................
else:
    如果没有异常执行这块代码

除了以上做法可能可读性差,不能简洁明了告诉我们每一个不同的异常的处理逻辑,所以我们可以使用多个except子句的如下方式 ,类似于多个catch子句:

number = input('please type a number(max=100):')

try:
    number = int(number)
    number = number + 1
except ValueError as e:
    print('Error: {}'.format(e))
except IOError as e:
    print('IOError: {}'.format(e))
finally:
    print("That's all!")

 

注意:except子句的数量没有限制,但使用多个except子句捕获异常时,如果异常类之间具有继承关系,则子类应该写在前面,否则父类将会直接截获子类异常。放在后面的子类异常也就不会执行。 但最多只有一个分支会被执行,所以except子句有排序先后问题

try 语句按如下方式工作:

  • 首先,执行 try 子句 (在 try 和 except 关键字之间的部分)。

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

  • 如果在 try 子句执行过程中发生了异常,那么该子句其余的部分就会被忽略。

    如果异常匹配于 except 关键字后面指定的异常类型,就执行对应的except子句。然后继续执行 try 语句之后的代码。

  • 如果发生了一个异常,在 except 子句中没有与之匹配的分支,它就会传递到上一级 try 语句中。

    如果最终仍找不到对应的处理语句,它就成为一个 未处理异常,终止程序运行,显示提示信息。 

2.2 try-finally 语句

try-finally 语句无论是否发生异常都将执行最后的代码finally里的代码。

NOTE:try…finally 的意义在于,就是我们在 try 代码块中执行了 return 语句,但是仍然会继续执行在 finally 中的代码块,所以我们一般用作处理资源的释放,但不捕获异常。

基本语法:

try:
<语句>
finally:
<语句>    #退出try时总会执行
raise

实例:

try:
    fh = open("testfile", "w")
    fh.write("这是一个测试文件,用于测试异常!!")
finally:
    print "Error: 没有找到文件或读取文件失败"

如果打开的文件没有可写权限,输出如下所示:

$ python test.py 
Error: 没有找到文件或读取文件失败

同样的例子也可以写成如下方式:

try:
    fh = open("testfile", "w")
    try:
        fh.write("这是一个测试文件,用于测试异常!!")
    finally:
        print "关闭文件"
        fh.close()
except IOError:
    print "Error: 没有找到文件或读取文件失败"

当在try块中抛出一个异常,立即执行finally块代码。

finally块中的所有语句执行后,异常被再次触发,并执行except块代码。参数的内容不同于异常。

当出现类似break,return等关键字,会先执行完finally块中的语句再进行break等操作。

2.3 try/except/finally语句块

完整版的语句块:

def div(a, b):
    try:
        print(a / b)
    except ZeroDivisionError:
        print("Error: b should not be 0 !!")
    except Exception as e:
        print("Unexpected Error: {}".format(e))
    else:
        print('Run into else only when everything goes well')
    finally:
        print('Always run into finally block.')

# tests
div(2, 0)
div(2, 'bad type')
div(1, 2)


Error: b should not be 0 !!
Always run into finally block.
Unexpected Error: unsupported operand type(s) for /: 'int' and 'str'
Always run into finally block.
0
Run into else only when everything goes well
Always run into finally block.
# Mutiple exception in one line
try:
    print(a / b)
except (ZeroDivisionError, TypeError) as e:
    print(e)

# Except block is optional when there is finally
try:
    open(database)
finally:
    close(database)

# catch all errors and log it
try:
    do_work()
except:    
    # get detail from logging module
    logging.exception('Exception caught!')
    
    # get detail from sys.exc_info() method
    error_type, error_value, trace_back = sys.exc_info()
    print(error_value)
    raise

 

总结如下

  1. except语句不是必须的,finally语句也不是必须的,但是二者必须要有一个,否则就没有try的意义了。
  2. except语句可以有多个,Python会按except语句的顺序依次匹配你指定的异常,如果异常已经处理就不会再进入后面的except语句。类似于catch语句,按照顺序匹配,所以保证最上层异常类型最小。不需要下层异常类型包含上层,但不能够出现上层异常类型包含下层的情况,此时下层异常类型永远无法捕获。
  3. except语句可以以元组形式同时指定多个异常,参见实例代码。并且指定一个对象相当于Exception e。
  4. except语句后面如果不指定异常类型,则默认捕获所有异常,你可以通过logging或者sys模块获取当前异常。
  5. 如果要捕获异常后要重复抛出,请使用raise,后面不要带任何参数或信息。类似于throws往上抛出。
  6. 不建议捕获并抛出同一个异常,请考虑重构你的代码。
  7. 不建议在不清楚逻辑的情况下捕获所有异常,有可能你隐藏了很严重的问题。
  8. 尽量使用内置的异常处理语句来替换try/except语句,比如with语句,getattr()方法。

2.4 异常的参数

一个异常可以带上参数,可作为输出的异常信息参数。具体需要捕获异常类型和异常类型的错误提示。类似于Exception e的格式。这个参数是否存在、是什么类型,依赖于异常的类型。

你可以通过except语句来捕获异常的参数,如下所示:

Python2中:

try:
    正常的操作
   ......................
except ExceptionType, Argument:
    你可以在这输出 Argument 的值...

注:在Python3中,原Python2的except Exception , ex的别名方法已经不能使用,逗号被认为是两种异常的分隔符,而不是取别名。 

 Python2和Python3中:Py3不支持直接输出参数的格式。

try:
    正常的操作
   ......................
except ExceptionType as e:
    你可以在这输出 e 的值...

         变量接收的异常值通常包含在异常的语句中。在元组的表单中变量可以接收一个或者多个值。元组通常包含错误字符串,错误数字,错误位置。

实例:

以下为单个异常的实例:

# 定义函数
def temp_convert(var):
    try:
        return int(var)
    except ValueError, Argument:
        print "参数没有包含数字\n", Argument

# 调用函数
temp_convert("xyz")

以上程序执行结果如下:

$ python test.py 
参数没有包含数字
invalid literal for int() with base 10: 'xyz'

Python3中执行:不支持这种方式。

  File "untitled1.py", line 12
    except ValueError, Argument:
                     ^
SyntaxError: invalid syntax

 Python 3只支持这样方式,不支持后接参数的形式,必须指定为一个参数。所以为了兼容Py2和Py3,需要用下述形式,而且功能更强大。

# 定义函数
def temp_convert(var):
    try:
        return int(var)
    except ValueError as e:
        print "参数没有包含数字\n", Argument

# 调用函数
temp_convert("xyz")

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

2.5 具体使用方法

python中try except处理程序异常的三种常用方法
方法一:捕获所有异常

try:  
    a=b  
    b=c  
except (ZeroDivisionError,Exception):
        print(ZeroDivisionError,":",Exception)

方法二:采用traceback模块查看异常
#引入python中的traceback模块,跟踪错误

import traceback  
try:  
    a=b  
    b=c  
except:  
    traceback.print_exc()

方法三:采用sys模块回溯最后的异常
#引入sys模块
 

import sys  
try:  
    a=b  
    b=c  
except:  
    info=sys.exc_info()  
    print info[0],":",info[1]
但是,如果你还想把这些异常保存到一个日志文件中,来分析这些异常,那么请看下面的方法:
把 traceback.print_exc() 打印在屏幕上的信息保存到一个文本文件中

输出sys.exc_type, sys.exc_value, sys.exc_traceback, limit, file等异常信息,实际上是以线程安全的方式去使用sys.exc_info()函数来获取相同的信息。 

import traceback
try:  
    a=b  
    b=c  
except:  
    f=open("c:log.txt",'a')  
    traceback.print_exc(file=f)  
    f.flush()  
    f.close()

2.6 主动抛出异常

我们可以使用raise语句自己触发异常。类似于Java的thow和thows(直接抛出自定义异常)主动抛出异常。此时可以让上层调用者捕获和处理该异常。更多的时候是抛出自定义类型。

raise唯一的一个参数指定了要被抛出的异常的实例,如果什么参数都不给,那么会默认抛出当前异常。

raise语法格式如下:

raise [Exception [, args [, traceback]]]

语句中 Exception 是异常的类型(例如,NameError)参数标准异常中任一种,args 是自已提供的异常参数。

最后一个参数是可选的(在实践中很少使用),如果存在,是跟踪异常对象。

作用:

(1)需要记录错误信息,然后将异常继续往上层传递,让上层去处理异常(类似于Java的throws)。

(2)需要主动弹出异常,作为警告或特殊处理(类似于Java的throw)。

实例:

一个异常可以是一个字符串,类或对象。 Python的内核提供的异常,大多数都是实例化的类,这是一个类的实例的参数。

定义一个异常非常简单,如下所示:

def functionName( level ):
    if level < 1:
        raise Exception("Invalid level!", level)
        # 触发异常后,后面的代码就不会再执行

注意:为了能够捕获异常,"except"语句必须有用相同的异常来抛出类对象或者字符串。

例如我们捕获以上异常,"except"语句如下所示:

try:
    正常逻辑
except Exception,err:
    触发自定义异常    
else:
    其余代码

实例:

# 定义函数
def mye( level ):
    if level < 1:
        raise Exception,"Invalid level!"
        # 触发异常后,后面的代码就不会再执行
try:
    mye(0)            # 触发异常
except Exception,err:
    print 1,err
else:
    print 2

执行以上代码,输出结果为:

$ python test.py 
1 Invalid level!

一般为了形成捕获链,重新抛出捕获的异常,都是用raise,不加参数。 

2.7 用户自定义异常

通过创建一个新的异常类,程序可以命名它们自己的异常。异常应该是典型的继承自Exception类,通过直接或间接的方式。异常的名字都以Error结尾,我们在为自定义异常命名的时候也需要遵守这一规范,就跟标准的异常命名一样。

以下为与RuntimeError相关的实例,实例中创建了一个类,基类为RuntimeError,用于在异常触发时输出更多的信息。

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

在try语句块中,用户自定义的异常后执行except块语句,变量 e 是用于创建Networkerror类的实例。

class Networkerror(RuntimeError):
    def __init__(self, arg):
        self.args = arg

在你定义以上类后,你可以触发该异常,如下所示:

try:
    raise Networkerror("Bad hostname")
except Networkerror,e:
    print e.args

2.8 Python 标准异常类

Python解析器会自动将通用异常类型名称放在内建命名空间中。

异常名称描述
BaseException所有异常的基类
SystemExit解释器请求退出
KeyboardInterrupt用户中断执行(通常是输入^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尚未实现的方法
SyntaxErrorPython 语法错误
IndentationError缩进错误
TabErrorTab 和空格混用
SystemError一般的解释器系统错误
TypeError对类型无效的操作
ValueError传入无效的参数
UnicodeErrorUnicode 相关的错误
UnicodeDecodeErrorUnicode 解码时的错误
UnicodeEncodeErrorUnicode 编码时错误
UnicodeTranslateErrorUnicode 转换时错误
Warning警告的基类
DeprecationWarning关于被弃用的特征的警告
FutureWarning关于构造将来语义会有改变的警告
OverflowWarning旧的关于自动提升为长整型(long)的警告
PendingDeprecationWarning关于特性将会被废弃的警告
RuntimeWarning可疑的运行时行为(runtime behavior)的警告
SyntaxWarning可疑的语法的警告
UserWarning用户代码生成的警告

异常类型组织结构如下: 

1 BaseException
 2  +-- SystemExit
 3  +-- KeyboardInterrupt
 4  +-- GeneratorExit
 5  +-- Exception
 6       +-- StopIteration
 7       +-- StandardError
 8       |    +-- BufferError
 9       |    +-- ArithmeticError
10       |    |    +-- FloatingPointError
11       |    |    +-- OverflowError
12       |    |    +-- ZeroDivisionError
13       |    +-- AssertionError
14       |    +-- AttributeError
15       |    +-- EnvironmentError
16       |    |    +-- IOError
17       |    |    +-- OSError
18       |    |         +-- WindowsError (Windows)
19       |    |         +-- VMSError (VMS)
20       |    +-- EOFError
21       |    +-- ImportError
22       |    +-- LookupError
23       |    |    +-- IndexError
24       |    |    +-- KeyError
25       |    +-- MemoryError
26       |    +-- NameError
27       |    |    +-- UnboundLocalError
28       |    +-- ReferenceError
29       |    +-- RuntimeError
30       |    |    +-- NotImplementedError
31       |    +-- SyntaxError
32       |    |    +-- IndentationError
33       |    |         +-- TabError
34       |    +-- SystemError
35       |    +-- TypeError
36       |    +-- ValueError
37       |         +-- UnicodeError
38       |              +-- UnicodeDecodeError
39       |              +-- UnicodeEncodeError
40       |              +-- UnicodeTranslateError
41       +-- Warning
42            +-- DeprecationWarning
43            +-- PendingDeprecationWarning
44            +-- RuntimeWarning
45            +-- SyntaxWarning
46            +-- UserWarning
47            +-- FutureWarning
48        +-- ImportWarning
49        +-- UnicodeWarning
50        +-- BytesWarning

 

三、高级使用方法

3.1 传递异常 re-raise Exception

捕捉到了异常,但是又想重新抛出它(传递异常),使用不带参数的raise语句即可:

def f1():
    print(1/0)

def f2():
    try:
        f1()
    except Exception as e:
        raise  # don't raise e !!!

f2()

在Python2中,为了保持异常的完整信息,那么你捕获后再次抛出时千万不能在raise后面加上异常对象,否则你的trace信息就会从此处截断。以上是最简单的重新抛出异常的做法,也是推荐的做法。

还有一些技巧可以考虑,比如抛出异常前你希望对异常的信息进行更新。

def f2():
    try:
        f1()
    except Exception as e:
        e.args += ('more info',)
        raise

Python3对重复传递异常有所改进,你可以自己尝试一下,不过建议还是遵循以上规则。

3.2 Exception 和 BaseException

当我们要捕获一个通用异常时,应该用Exception还是BaseException?这两个异常到底有啥区别呢? 请看它们之间的继承关系。

BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration...
      +-- StandardError...
      +-- Warning...

从Exception的层级结构来看,BaseException是最基础的异常类,Exception继承了它。BaseException除了包含所有的Exception外还包含了SystemExit,KeyboardInterrupt和GeneratorExit三个异常。

由此看来你的程序在捕获所有异常时更应该使用Exception而不是BaseException,因为被排除的三个异常属于更高级别的异常,合理的做法应该是交给Python的解释器处理。

3.3 except Exception as e和 except Exception, e

as 表示将异常重命名。

代码示例如下:

try:
    do_something()
except NameError as e:  # should
    pass
except KeyError, e:  # should not
    pass

在Python2的时代,你可以使用以上两种写法中的任意一种。在Python3中你只能使用第一种写法,第二种写法已经不再支持。第一个种写法可读性更好,而且为了程序的兼容性和后期移植的成本,请你果断抛弃第二种写法。

3.4 raise "Exception string"

把字符串当成异常抛出看上去是一个非常简洁的办法,但其实是一个非常不好的习惯。

if is_work_done():
    pass
else:
    raise "Work is not done!" # not cool

上面的语句如果抛出异常,那么会是这样的:

Traceback (most recent call last):
  File "/demo/exception_hanlding.py", line 48, in <module>
    raise "Work is not done!"
TypeError: exceptions must be old-style classes or derived from BaseException, not str

       这在 Python2.4 以前是可以接受的做法,但是没有指定异常类型有可能会让下游没办法正确捕获并处理这个异常,从而导致你的程序难以维护。简单说,这种写法是过时的,应该摒弃,应该抛出一个具体类型。

3.5 使用内置的语法范式代替try/except

       Python 本身提供了很多的语法范式简化了异常的处理,比如for语句就处理了的StopIteration异常,让你很流畅地写出一个循环。with语句在打开文件后会自动调用finally并关闭文件(预定义清理行为)。我们在写 Python 代码时应该尽量避免在遇到这种情况时还使用try/except/finally的思维来处理。

如果with语句块中触发异常,会调用默认的异常处理器处理,而且文件仍然能够正常关闭。

# should not
try:
    f = open(a_file)
    do_something(f)
finally:
    f.close()

# should 
with open(a_file) as f:
    do_something(f)

再比如,当我们需要访问一个不确定的属性时,有可能你会写出这样的代码:

try:
    test = Test()
    name = test.name  # not sure if we can get its name
except AttributeError:
    name = 'default'

其实你可以使用更简单的getattr()来达到你的目的。

name = getattr(test, 'name', 'default')

 

在第一个方法中需要在finally子句中再判断f是否为空,然后确定是否关闭。 

四、断言

断言(assert):当程序运行到某个节点的时候,就断定某个变量的值必然是什么,或者是对象必然拥有某个属性等。简单点来说的话,就是断定是什么东西就必然是什么东西,如果不是,就抛出断言错误异常。

断言应该用于如下情况:

  • 防御性的编程
  • 运行时对程序逻辑的检测
  • 合约性检查(比如前置条件,后置条件)
  • 程序中的常量
  • 检查文档

在测试用例中,执行完测试用例后,最后一步是判断测试结果是pass还是fail,自动化测试脚本里面一般把这种生成测试结果的方法称为断言。

4.1 基本使用方法

assert语句根据后面的表达式的真假来控制程序流。若为True,则往下执行。若为False,则中断程序并调用默认的异常处理器,同时输出指定的提示信息。也就是触发一个带可选错误信息的AssertionError。

assert断言语句为raise-if-not,用来测试表示式,其返回值为假,就会触发异常。

格式:

assert expression,'information'

Example:

#!/usr/bin/env python
def testAssert(x):
    assert x < 1,'Invalid value'
testAssert(1)
print 'Valid value'

output:

AssertionError: Invaild value

4.2 断言函数

以上是基本断言用法。还有一些已经定义好的断言函数可以使用。

常用的断言函数:

五、异常处理和断言的对比

5.1 什么时候使用断言

(1)可以使用断言去检查代码中的确定量。

确定量怎么理解?在当前情境下,确定量总会满足特定条件。比如,在某段代码里,变量 x 的值始终应该在 0 到 1 之间。

(2)断言能够帮助别人或未来的你理解代码,找出程序中逻辑不对的地方。

一方面,断言会提醒你某个对象应该处于何种状态,另一方面,如果某个时候断言为假,会抛出 AssertionError 异常,很有可能终止程序。

(3)参数校验

有的时候断言会被用到函数参数校验的地方,我们应该避免这种使用方式。因为,如果 Python 以 -O 选项执行的话,assert 语句会被跳过。这样的话,我们的校验语句都会失效。断言为假触发的异常的语义相比于一般的异常也不太明确。比如,当需要使用 int 类型的时候用户传入 string 类型手动触发一个 TypeError ,或是当需要正数但接收到负数的时候手动触发一个 ValueError ,都比 AssertionError好理解一些。

5.2 小结

  • 使用断言去检测程序中理论上不应该出现的情况。注意 Python 带 -O 选项执行时,断言会被忽略。
  • 当由用户输入或者外部环境(比如网络延迟、文件不存在等)引起的问题时,我们应抛出异常。
  • 尽量避免抛出或捕获 [Base]Exception 。

六、总结

(1)总体来说使用方法类似于Java的try/catch/finally,只不过把catch换成了except。异常类型,参数,自定义异常类,主动抛出异常等Java都有。

(2)有一个异常处理的问题,不管是Python,Java还是C++等都需要考虑。因为本人是学信息安全的,所以很多时候需要考虑安全问题。如果在一个公司的实际的项目里,每一次都打印异常信息,将是一件很危险的事,会给黑客提供很多信息量;而且也不是一个用户友好的开发实现。所以一是保证异常捕获不暴露具体信息,二是要形成一个异常捕获链,传递异常。

(3)避免在catch语句块中干一些没意义的事情,捕获异常也是需要成本的。

(4)只处理你知道的异常,避免捕获所有异常然后吞掉它们,而你并不知道这个错误。

(5)不要使用异常来控制流程,那样你的程序会无比难懂和难维护,可读性很差。

(6)如果有需要,切记使用finally来释放资源。

(7)如果有需要,请不要忘记在处理异常后做清理工作或者回滚操作。

è¿éåå¾çæè¿°

Python 处理错误和异常 在 Python 中,我们可以通过创建一个新类来定义自己的自定义异常,该类必须派生于内置的Exception类或其子类。为了说明这个概念,我们将修改之前的示例,定义两个自定义异常类来替换内置的TypeError和Exception错误类型。新的自定义异常类将从TypeError和Exception类派生。super().__init__("%r 不是数字,只充许数字。" % value)super().__init__("%r 是负数,不支持负数。 阅读详情

相关推荐

SyntaxError :invalid syntax错误解决办法

SyntaxError :invalid syntax错误解决办法:1版本问题: 因为python2和python3是不兼容的,所以一些可以在python2上运行的代码不一定可以在python3上运行;可以尝试更换版本; SyntaxError :invalid syntax错误解决办法:2路径问题: 记得仔细查看自己的路径是否正确; SyntaxError :invalid syntax错误解决办法:3粗心问题: 忘记在 if , elif , else , for , while , class ,de

计算机毕业论文源码,学生个人网页制作html源码。贴近用户做网络推广和互联网优化。 2万+

【python】错误SyntaxError: invalid syntax的解决方法总结

今天学习了python,然而刚开始就出了一个难题,明明代码没有一点问题,可是每次运行都会显示 “SyntaxError: invalid syntax”。 “SyntaxError: invalid syntax” 的意思就是 语法错误; 经过查询解决了这个问题,所以总结一个这个问题的解决方法: 版本问题: 因为python2和python3是不兼容的;可以尝试更换版本; 粗心问题: 忘...

赫菲斯托斯,, 227万+

Python一直报错:SyntaxError: invalid syntax 的原因及解决办法

本篇文章主要讲解 python报错提示 无效语法 SyntaxError: invalid syntax 的原因及解决办法 日期:2022年2月18日 作者:任聪聪 报错现象 python报错如下,但是没有发现那里不对。 造成报错的原因汇总 如上报错的代码行 elif 后,经过细心排查,造成的原因是由于空格和":"[中文的]。而此类报错实际上是提示语法错误,因为python对编码的格式、语句等都有严格的要求,如果语法不对或者语法缺胳膊少腿,就会报这个错误。 解决和排查方式 SyntaxError: i.

任聪聪的博客 39万+

已解决SyntaxError: invalid syntax

已解决(Python语法错误)SyntaxError: invalid syntax

努力让自己发光,对的人才能迎着光而来 2万+

Python学习: 错误和异常

在Python中,用户可以通过创建新的类来定义自定义异常。这些自定义异常是内置异常类(如ExceptionValueError等)的子类,它们可以根据特定的程序要求来提供更多的细节信息。在这个示例中,我们定义了一个名为的自定义异常,它继承自内置的Exception类。在初始化方法__init__中,我们可以定义异常的初始化逻辑,并设置异常的消息。if x < 0:return xtry:num = -5在上面的示例中,我们定义了函数来检查输入的数字是否为非负数,如果是负数则抛出自定义异常。在。

百锦再的博客 4万+

【Python技术学习】- python 错误和异常

你可以通过创建一个新的异常类来拥有自己的异常。异常类继承自 Exception 类,可以直接继承,或者间接继承,例如:>>> try:')在这个例子中,类 Exception 默认的 __init__() 被覆盖。当创建一个模块有可能抛出多种不同的异常时,一种通常的做法是为这个包建立一个基础异常类,然后基于这个基础类为不同的错误情况创建不同的子类:pass"""allowed."""

xiaoli8748的专栏 1563

python学习笔记系列----(六)错误和异常

python学习笔记系列----(六)错误和异常

wangchaoqi1985的博客 112

P201-1-answer.py

P201-1-answer.py

python存储和读取数据时出现错误_Python入门学习系列——Python文件和异常

从文件中读取数据首先准备一个文本文件,文件中存储着普通文本数据。读取文件需要调用open()和read()函数。读取整个文件代码示例:withopen('pi_digits.txt')asfile_object:contents=file_object.read()print(contents)open()函数在读取文件之前,必须先要打开文件,这样才能访问它。打开文件需要调用open()函数,它接...

weixin_39889214的博客 208

微信小程序scroll-view,点击menu,滚动到锚点;滚动到锚点,激活menu。

首先看看效果图1、首先是点击菜单,滚动列表,这个实现比较简单。直接使用scroll-view 的 scroll-into-view属性,小程序文档。&lt;view class='container'&gt; &lt;!-- 菜单 --&gt; &lt;view class='menu'&gt; &lt;ul&gt; &lt;!-- scrollList 修改cate --&g...

weixin_39834214的博客 1万+

私有化大模型部署:企业AI应用的核心架构

私有化大模型部署不是“一次性项目”,而是企业AI的“长期主义”投资——它需要企业投入时间、金钱和精力,但回报是数据安全、定制化能力、核心竞争力的提升。就像“自家厨房”一样,私有化大模型可能初期麻烦,但一旦搭建起来,就能为企业“做”出符合自己口味的“特色菜”,而这些“特色菜”,正是企业在激烈竞争中的“护城河”。愿你能构建属于自己的“AI大脑”,让技术真正赋能业务,让复杂变简单,让深奥变通透。附录:私有化大模型部署架构图(注:可根据企业需求调整,此为通用架构)

AI天才研究院 1019

Python的错误和异常,异常的处理

该篇讲述如何正确理解和有效处理错误与异常

qq_52758588的博客 1772

OpenClaw与Ollama本地AI部署指南

AI模型本地化部署是当前企业数字化转型的关键技术,通过开源框架Ollama可以在消费级硬件上运行大语言模型。本文以OpenClaw多智能体系统为例,详解从环境配置到模型优化的全流程实践,特别针对国内开发者遇到的网络问题提供了镜像加速等解决方案。这种私有化部署方案尤其适合金融数据分析、企业知识管理等对数据安全要求高的场景,通过模块化设计实现多智能体协作,同时保持对NVIDIA显卡和普通CPU的兼容性。

weixin_34302561的博客 396

Python的错误和异常

python的错误和异常

一个想交朋友的陌生人 1469

黑猫带你学Nand第8篇:NandFlash的供电情况详解

是指在任何工作条件下,设备允许的最大电压、电流、功率以及温度等参数的界限值。

黑猫奥利奥的博客 1146

基于Python的CT骨料图像分割与STL批量导出完整指南

本文介绍了一套完整的Python解决方案,用于CT骨料图像的分割与STL导出。针对CT图像中颗粒粘连、噪声伪影等技术难点,提出基于分水岭算法的分割策略,结合距离变换与标记控制实现颗粒分离。内容包括环境配置、数据读取与预处理、Otsu阈值分割、分水岭算法实现、表面提取与STL导出等关键步骤。教程提供详细代码及解释,帮助读者从CT体数据出发,最终生成每个颗粒的三维网格文件,便于后续定量分析和数值模拟。

huanghm88的专栏 235

python异常和错误有什么区别_python的错误和异常

python错误和异常错误错误分为语法错误和逻辑错误语法错误>>> ifFile "", line 1if^SyntaxError: invalid syntax程序执行过程中,python解释器会检测你的程序是否存在语法错误,如果程序出错python解释器会指出出错的一行,并且在最先找到的 错误的文职标记了一个小小的箭头。逻辑错误>>> 1/0Traceback (most recent cal...

weixin_39852688的博客 2728

软考高级架构师笔记-10数学计算题

专栏《软考高级架构设计师》更新了,本章列举了10个场景计算题的解法,温故而知新,大家快来卷一卷

java后端开发的博客,不仅仅是后端开发 1594

我的Python学习日记(九):错误和异常

我的Python学习日记。

2201_76050457的博客 1110

反应动力学仿真软件:CHEMKIN_(12).CHEMKIN与其他软件的接口

通过上述介绍,我们详细探讨了如何将 CHEMKIN 与 MATLAB、Python、COMSOL、Aspen Plus 和 Ansys Fluent 等软件工具进行接口配置和数据交互。这些接口不仅能够显著提升 CHEMKIN 在反应动力学仿真中的应用效果,还能充分利用其他软件工具的强大功能,实现更复杂的数据处理和分析。希望这些内容对您在化学反应动力学仿真中的工作有所帮助。

kkchenjj的博客 1137

vue:npm安装pnpm报错,npm ERR! code ENOTFOUND,npm ERR! syscall getaddrinfo,npm ERR! errno ENOTFOUND详细排查解决!

vue2 vue3,npm install -g pnpm 安装出现错误,安装pnpm及解决安装失败问题,解决 npm无法安装pnpm问题,npm 安装 pnpm 时 报错 npm ERR! code ENOTFOUND,pnpm无法安装报错,vue npm install -g pnpm安装报错,request to http://registry.cnpmjs.org/pnpm failed, reason: getaddrinfo ENOTFOUND registry.cnpmjs.org,安装pnp

✅ 精选推荐文章 3608

python异常和错误的区别_python:错误、异常

1、错误语法错误:代码不符合解释器或者编译器语法,例如 缩进字符、循环语句的冒号逻辑错误:不完整或不合法输入、算法问题,比如0作除数2、异常程序遇到逻辑或者算法问题运行过程中计算机错误(内存不够或IO错误)这两个或抛出异常,如果没有手动对其进行处理,那么此异常就会被解释器捕获,处理的方法为忽略或者终止程序3、错误和异常的区别错误是代码运行前错误是非正常的,不应该出现的,比如:缩进、循环语句的冒号异...

weixin_39620099的博客 4014

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

python中错误和异常区别

这是由于程序占用的内存超出了系统所能提供的范围。比如,当你试图创建一个极大的列表或者其他数据结构,耗尽了内存资源时就会出现这个错误。,这是一个运行时异常,因为在数学上除数不能为 0,程序的这个操作不符合预期的数学规则。块用于确保文件最终被关闭,即使在读取文件过程中出现了文件不存在的异常。,因为这是一个基本的语法违反。这种错误会阻止程序的正常编译或加载。这里遗漏了冒号,Python 解释器在解析代码时就会抛出。这段代码尝试读取一个不存在的文件,所以会出现。

m0_52951519的博客 1229

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Python 错误和异常

程序中的错误一般被称为 Bug,无可否认,这几乎总是程序员的错。。。

青春不老,奋斗不止! 7176

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

上一篇: Python学习系列之exit语句
下一篇: Python学习系列之多线程
answer3lin
博客等级 码龄11年 138粉丝 61原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值