[PYTHON] 核心编程笔记之十-Python错误和异常

简介:

10.1 什么是异常

10.1.1 错误

错误时语法或是逻辑上的,语法错误指示软件的结构上有错误,导致不能被解释器解释或编译器无法编译

当Python检测到一个错误时,解释器就会支出当前流已经无法继续执行下去,这时就出现了异常


10.1.2 异常


10.2 Python中的异常


例:

NameError: 尝试访问一个未声明的变量

>>> foo

Traceback (most recent call last):

 File "<stdin>", line 1, in <module>

NameError: name 'foo' is not defined


除数为零:

>>> 1/0

Traceback (most recent call last):

 File "<stdin>", line 1, in <module>

ZeroDivisionError: integer division or modulo by zero


Python解释器语法错误:

>>> for

 File "<stdin>", line 1

   for

     ^

SyntaxError: invalid syntax


请求的索引超出序列范围:

>>> aList = []

>>> aList[0]

Traceback (most recent call last):

 File "<stdin>", line 1, in <module>

IndexError: list index out of range


请求一个不存在的字典关键字:

>>> aDict = {'host':'earth','port':80}

>>> print aDict['server']

Traceback (most recent call last):

 File "<stdin>", line 1, in <module>

KeyError: 'server'


输入/输出错误

>>> f = open('haha')

Traceback (most recent call last):

 File "<stdin>", line 1, in <module>

IOError: [Errno 2] No such file or directory: 'haha'


尝试访问未知的对象属性


>>> class myClass(object):

...   pass

...

>>> myInst = myClass()

>>> myInst.bar = 'spam'

>>> myInst.bar

'spam'

>>> myInst.foo

Traceback (most recent call last):

 File "<stdin>", line 1, in <module>

AttributeError: 'myClass' object has no attribute 'foo'


10.3 检测和处理异常:

异常可以通过try语句来检测,任何在try语句块里的代码都会被检测,检查有无异常发生

try语句有两种形式:

try-except和try-finally

一个try语句可以对应一个或多个except子句,但只能对应一个finally子句,或一个try-except-finally复合语句


10.3.1 try-except 语句


try:

   try_suite # watch for exceptions here 监控这里的异常

except Exception[,reason]:

   except_suite   # exception-handling code 异常处理代码


例:

>>> try:

...     f = open('haha','r')

... except IOError,e:

...     print 'could not open file:',e

...

could not open file: [Errno 2] No such file or directory: 'haha'


10.3.2 封装内建函数


>>> float(12345)

12345.0

>>> float('12345')

12345.0

>>> float('123.45e67')

1.2345e+69

>>> float('foo')      

Traceback (most recent call last):

 File "<stdin>", line 1, in <module>

ValueError: could not convert string to float: foo

>>> float(['this is',1,'list'])

Traceback (most recent call last):

 File "<stdin>", line 1, in <module>

TypeError: float() argument must be a string or a number


如果参数类型正确,但值不可转换为浮点数,那么将引发ValueError异常


安全的调用float()函数:

我们创建一个封装函数,safe_float(),第一次改进中我们搜索并忽略ValueError

>>> def safe_float(obj):

...     try:

...        return float(obj)

...     except ValueError:

...        pass

...

>>> safe_float('haha')

>>> safe_float('123')

123.0


以上不足在于出现错误无返回任何信息,我们至少应该显式的返回None


>>> def safe_float(obj):

...     try:

...        retval = float(obj)

...     except ValueError:

...        retval = 'None'

...     return retval

...

>>> safe_float('123')

123.0

>>> safe_float('haha')

'None'


>>>def safe_float(obj):

...     try:

...        retval = float(obj)

...     except ValueError:

...        retval = 'could not convert non-number to float'

...     return retval

...

>>> safe_float('123')

123.0

>>> safe_float('bad input')

'could not convert non-number to float'


但如果传递一个非法对象,还是会出问题

>>> safe_float({'a':'Dict'})

Traceback (most recent call last):

 File "<stdin>", line 1, in <module>

 File "<stdin>", line 3, in safe_float

TypeError: float() argument must be a string or a number


10.3.3 带有多个except的try语句


except Exception1[, reason]:

   suite_for_exception_Exception1

except Exception2[, reason]:

   suite_for_exception_Exception2


例:

>>> def safe_float(obj):

...     try:

...         retval = float(obj)

...     except ValueError:

...         retval = 'could not convert non-number to float'

...     except TypeError:

...         retval = 'object type cannot be converted to float'

...     return retval

...


使用错误的参数调用这个函数:

>>> safe_float('xyz')

'could not convert non-number to float'

>>> safe_float(())

'object type cannot be converted to float'

>>> safe_float(200L)

200.0

>>> safe_float(45.67000)

45.670000000000002


10.3.4 处理多个异常的except语句:


except (Exception1,Exception2)[, reason]:

   suite_for_exception_Exception1_and_Exception2


except (Exc1[,Exc2[, ... ExcN]])[, reason]:

   suite_for_exceptions_Exc1_and_ExcN


要求safe_float()函数中的所有异常必须使用同样的代码:


>>> def safe_float(obj):

...    try:

...       retval = float(obj)

...    except(ValueError,TypeError):

...       retval = 'argument must be a number or numeric string'

...    return retval

...


现在,错误的输出会返回相同字符串:


>>> safe_float('Spanish Inquisition')

'argument must be a number or numeric string'

>>> safe_float([])

'argument must be a number or numeric string'

>>> safe_float('1.6')

1.6000000000000001

>>> safe_float(1.6)

1.6000000000000001

>>> safe_float(932)

932.0


10.3.5 捕获所有异常:


try:

   :

except Exception,e:

   # error,occurred,log 'e',etc


不推荐:

try:

   :

except Exception,e:

   # error,occurred,etc.


捕获Python需要退出的异常:

try:

   :

except(KeyboardInterupt,SystemExit):

   # user wants to quit

   raise # reraise back to caller

except Exception:

   # handle real errors


当你有了一个Exception处理器后,你不必为这两个异常创建额外的处理器


try:

   :

except Exception,e:

   # handle real errors


如果你确实需要捕获所有异常,那么你就得使用新的BaseExcption:


try:

   :

except BaseException,e:

   # handle all errors


注: 不要处理并忽略所有错误

try:

   large_block_of_code #bandage of large piece of code

except Exception: # same as except:

   pass # blind eye ignoring all errors


10.3.6 异常参数:


# single exception

except Exception[, reason]:

   suite_for_Exception_with_Argument


# multiple exceptions

except (Exception1,Exception2,...,ExceptionN)[, reason]:

   suite_for_Exception1_to_ExceptionN_wih_Argument


例:传参给内建float函数一个无效对象,引发TypeError异常:


>>> try:

...     float(['float() does not','like lists', 2])

... except TypeError,diag: # capture diagnostic info

...     pass

...

>>> type(diag)

<type 'exceptions.TypeError'>

>>> print diag

float() argument must be a string or a number


我们首先在一个try语句块中引发一个异常,随后简单的忽略了这个异常,但保留了错误的信息,调用内置type()函数,我们可以确认我们的异常的确是TypeError异常类的实例,最后我们队异常诊断参数调用print以显示错误


为了获取更多关于异常的信息,我们可以调用该实例的__class__属性,它标示了实例是从什么类实例化而来,类对象也有属性


>>> diag

TypeError('float() argument must be a string or a number',)

>>> diag.__class__

<type 'exceptions.TypeError'>

>>> diag.__class__.__doc__

'Inappropriate argument type.'

>>> diag.__class__.__name__

'TypeError'


我们用字符串化(string representation)的异常参数来替换单一的错误信息


>>> def safe_float(object):

...    try:

...       retval = float(object)

...    except(ValueError, TypeError), diag:

...       retval = str(diag)

...    return retval


当我们提供的safe_float()参数给的不恰当时,虽然只有一条捕获语句,但可以获得如下信息:


>>> safe_float('xyz')

'could not convert string to float: xyz'

>>> safe_float({})  

'float() argument must be a string or a number'


10.3.7 在应用使用我们封装的函数:


我们将在一个迷你应用中特地的使用这个函数,它将打开信用卡交易数据文件,加载所有交易,包括解释的字符串,下面是一个示例的carddate.txt文件:


# cat carddata.txt

# carddata.txt previous balance

25

debits

21.64

541.24

25

credits

-25

-541.24

finance charge/late fees

7.30

5


# vi cardrun.py

----------------------------

#!/usr/bin/env python


def safe_float(obj):

   'safe version of float()'

   try:

       retval = float(obj)

   except(ValueError,TypeError),diag:

       retval = str(diag)

   return retval


def main():

   'handles all the data processing'

   log = open('cardlog.txt','w')

   try:

       ccfile = open('carddata.txt','r')

   except IOError,e:

       log.write('no txns this month\n')

       log.close()

       return


   txns = ccfile.readlines()

   ccfile.close()

   total = 0.00

   log.write('accout log:\n')


   for eachTxn in txns:

       result = safe_float(eachTxn)

       if isinstance(result,float):

           total += result

           log.write('data... processed\n')

       else:

           log.write('ignored: %s' %result)

   print '$%.2f(new balance)' % (total)

   log.close()


if __name__ == '__main__':

   main()

----------------------------


# python cardrun.py

-------------------------

$58.94(new balance)

---------------------------


# cat cardlog.txt

------------------------------  

accout log:

ignored: could not convert string to float: # carddata.txt previous balance

data... processed

ignored: could not convert string to float: debits

data... processed

data... processed

data... processed

ignored: could not convert string to float: credits

data... processed

data... processed

ignored: could not convert string to float: finance charge/late fees

data... processed

data... processed

ignored: could not convert string to float:

----------------------------------


10.3.8 else 子句


在try范围中没有异常被检测到时,才会执行else子句


import 3rd_party_module


log = open('logfile.txt','w')

try:

   3rd_party_module.function()

except:

   log.write("*** caught exception in module\n")

else:

   log.write("*** no exception caught\n")


log.close()


10.3.9 finally子句


try-except-else-finally语法示例:

try:

   A

except MyException: B

else: C

finally: D


10.3.10 try-finally语句:

无论try中是否有异常触发,finally代码段都会被执行


try:

   try_suite

finally:

   finally_suite # 无论如何都执行


当在try范围中产生一个异常时,会立即跳转到finally语句段,当finally所有代码执行完毕,才会继续向上一层引发异常


try:

   cofile = open('carddata.txt')

except IOError:

   log.write('no txns this month\n')

txns = cofile.readlines()

ccfie,close


但有很多原因会导致readlines()失败,其中一种就是carddata.txt存在于网络(或软盘上),本身介质的不稳定导致不能稳定读取

我们可以把这一小段读取数据的代码整个放入try子句范围中:


try:

   cofile = open('carddata.txt')

   txns = cofile.readlines()

   ccfie.close

except IOError:

   log.write('no txns this month\n')


如果出于一些原因readlines()调用失败,异常处理会去继续执行except中的子句,从而不会去关闭文件(ccfie.close)

如何在出现错误后,仍旧可以关闭文件,我们可以通过try-finally来实现:


ccfile = None

try:

 try:

     cofile = open('carddata.etc')

     txns = cofile.readlines()

     ccfie.close

 except IOEorror:

     log.write('no txns this month\n')

finally:

   if ccfile:

ccffle.close()


以下代码本质与之前干的同样的工作,区别在于关闭文件发生在异常处理器将错误写入日志之前,这是因为finally会自动重新引发异常


ccfile = None

try:

 try:

     cofile = open('carddata.etc')

     txns = cofile.readlines()

 finally:

     if ccfile:

     ccffle.close()

except IOError:

     log.write('no txns this month\n')


10.3.11 try-except-else-finally


try:

   try_suite


except Exception1:

   suite_for_Exception1


except (Exception2,Exception3,Exception4):

   suite_for_Exceptions_2_3_and_4


except Exception5,Argument5:

   suite_for_excetion5_plus_argument


except (Exception6,Exception7),Argument67:

   suite_for_excetion6_and_7_plus_argument


except:

   suite_for_all_other_exceptions


else:

   no_exceptions_detected_suite


finally:

   always_execute_suite


10.4 上下文管理

10.4.1 with语句


with context_expr [as var]:

   with_suite


例:

with open('/etc/passwd','r') as f:

   for eachLine in f:

# ...do stuff with eachLine or f...


10.4.2 *上下文管理协议


10.5 *字符串作为异常


10.6 触发异常

到目前为止,我们所见到的异常都是由解释器引发的,由于执行期间的错误而引发,程序员在编写API时也希望在遇到错误的输入时触发异常,为此,Python提供了一种机制让程序员明确的触发异常:这就是raise语句:


10.6.1 raise语句


raise [SomeException [, args[, traceback]]]


raise语句的用法


rasie 语法描述

raise exclass触发一个异常,从exclass生成一个实例(不含任何异常参数)

raise exclass()同上,除了现在不是类;通过函数调用操作符作用于类名生成一个新的exclass实例,同样也没有异常参数

raise exclass,args同上,但同时提供的异常参数args,可以是一个参数也可以元祖

raise exclass(args)同上

raise exclass,args, tb同上,但提供一个追踪对象tb供使用

raise exclass,instance通过实例触发异常

raise instance通过实例触发异常

raise string触发字符串异常

raise string,args触发伴随着args

raise string,args,tb同上,但提供一个追踪对象tb供使用

raise重新触发前一个异常,如果之前没有异常,触发TypeError


10.7 断言

断言是一句必须等价于布尔真的判定,此外,发生异常也意味着表达式为假

可以理解为是raise-if-not语句,如果返回值是假,触发异常


10.7.1 断言语句


assert expression[, arguments]


assert用法:


assert 1 == 1

assert 2 +2 == 2 * 2

assert len(['my list', 12]) < 10

assert range(3) == [0, 1, 2]


AssertionError异常和其他异常一样可以用try-except语句块捕捉,如果没有捕捉,它将终止程序运行而且提供一个如下的traceback:


>>> assert 1 == 0

Traceback (most recent call last):

 File "<stdin>", line 1, in <module>

AssertionError


我们可以提供一个异常参数给我们的assert命令:


>>> assert 1 == 0 , 'One dose not equal zero silly!'

Traceback (most recent call last):

 File "<stdin>", line 1, in <module>

AssertionError: One dose not equal zero silly!


用try-except语句捕获AssertionError异常:


>>> try:

...     assert 1 == 0, 'One does not equal zero silly!'

... except AssertionError,args:                      

...     print '%s: %s' %(args.__class__.__name__, args)

...

AssertionError: One does not equal zero silly!


例:

def assert(expr, args=None):

   if __debug__ and not expr:

raise AssertionError,args


10.8 标准异常:


表10.2 列出了所有的Python当前的标准异常集,所有的异常都是内建的,所以它们在脚本启动前或在互交命令行提示符出现时已经是可用的了


表10.2 Python内建异常

(略)


10.9 创建异常:


例:

--------------------------------------

#!/usr/bin/env python


import os,socket,errno,types,tempfile


class NetworkError(IOError):

   pass


class FileError(IOError):

   pass


def updArgs(args,newarg=None):

   if isinstance(args,IOError):

myargs = []

myargs.extend([arg for arg in args])

   else:

myargs = list(args)


   if newarg:

myargs.append(newarg)

   return tuple(myargs)


def fileArgs(file, mode, args):

   if args[0] == errno.EACCES and 'access' in dir(os):

perms = ''

permd = {'r': os.R_OK, 'w': os.W_OK, 'x': os.X_OK}

pkeys = permd.keys()

pkeys.sort()

pkeys.reverse()


       for eachPerm in 'rwx':

   if os.access(file, permd[eachPerm]):

       perms += eachPerm

   else:

       perms += '-'


       if isinstance(args,IOError):

   myargs = []

   myargs.extend([arg for arg in args])

       else:

   myargs = list(args)


       myargs[1] = "'%s' %s (perms: '%s')" %(mode,myargs[1],perm)


       myargs.append(args.filename)

   else:

myargs = args


   return tuple(myargs)


def myconnect(sock,host,port):

   try:

sock.connect((host,port))

   except socket.error, args:

myargs = updArgs(args)


   if len(myargs) == 1:

myargs = (errno,ENXIO, myargs[0])

raise NetworkError, updArgs(myargs, host + ':' + str(port))


def myopen(file,mode='r'):

   try:

fo = open(file,mode)

   except IOError,args:

raise FileError, fileArgs(file, mode, args)


   return fo


def testfile():

   file =  tempfile.mktemp()

   f = open(file,'w')

   f.close()


   for eachTest in ((0, 'r'), (0100, 'r'),(0400,'w'),(0500, 'w')):

try:

   os.chmod(file, eachTest[0])

   f = myopen(file, eachTest[1])

except FileError, args:

   print "%s: %s" %(args.__class__.__name__, args)

else:

   print file, "opened ok... perm ignored"


   f.close()


   os.chmod(file,0777)

   os.unlink(file)


def testnet():

   s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

   for eachHost in ('deli', 'www'):

try:

   myconnect(s, 'deli', 8080)

except NetworkError, args:

   print "%s: %s" %(args.__class__.__name__, args)


if __name__ == '__main__':

   testfile()

   testnet()


--------------------------------------


10.10 为什么用异常(现在)?


10.11 到底为什么要异常?


10.12 异常和sys模块


>>> try:

...     float('abc123')

... except:

...     import sys

...     exc_tuple = sys.exc_info()

...

>>> print exc_tuple

(<type 'exceptions.ValueError'>, ValueError('could not convert string to float: abc123'), <traceback object at 0x7f1412e09fc8>)

>>>

>>> for eachItem in exc_tuple:

...     print eachItem

...

<type 'exceptions.ValueError'>

could not convert string to float: abc123

<traceback object at 0x7f1412e09fc8>


我们从sys.exc_info()得到的元祖中是:

exc_type: 异常类

exc_value: 异常类的实例

exc_traceback: 追踪对象


10.13 相关模块

模块描述

exceptions内建异常(永远不用导入这个模块)

contectliba为使用with语句的上下文对象工具

sys包含各种异常相关的对象和函数


     本文转自 showerlee 51CTO博客,原文链接:http://blog.51cto.com/showerlee/1330268,如需转载请自行联系原作者


相关文章
|
11天前
|
存储 数据挖掘 开发者
Python编程入门:从零到英雄
在这篇文章中,我们将一起踏上Python编程的奇幻之旅。无论你是编程新手,还是希望拓展技能的开发者,本教程都将为你提供一条清晰的道路,引导你从基础语法走向实际应用。通过精心设计的代码示例和练习,你将学会如何用Python解决实际问题,并准备好迎接更复杂的编程挑战。让我们一起探索这个强大的语言,开启你的编程生涯吧!
|
4天前
|
Python
Python编程入门:从零开始的代码旅程
本文是一篇针对Python编程初学者的入门指南,将介绍Python的基本语法、数据类型、控制结构以及函数等概念。文章旨在帮助读者快速掌握Python编程的基础知识,并能够编写简单的Python程序。通过本文的学习,读者将能够理解Python代码的基本结构和逻辑,为进一步深入学习打下坚实的基础。
|
8天前
|
数据采集 存储 数据处理
Python中的多线程编程及其在数据处理中的应用
本文深入探讨了Python中多线程编程的概念、原理和实现方法,并详细介绍了其在数据处理领域的应用。通过对比单线程与多线程的性能差异,展示了多线程编程在提升程序运行效率方面的显著优势。文章还提供了实际案例,帮助读者更好地理解和掌握多线程编程技术。
|
11天前
|
存储 人工智能 数据挖掘
Python编程入门:打造你的第一个程序
本文旨在为初学者提供Python编程的初步指导,通过介绍Python语言的基础概念、开发环境的搭建以及一个简单的代码示例,帮助读者快速入门。文章将引导你理解编程思维,学会如何编写、运行和调试Python代码,从而开启编程之旅。
34 2
|
12天前
|
存储 Python
Python编程入门:理解基础语法与编写简单程序
本文旨在为初学者提供一个关于如何开始使用Python编程语言的指南。我们将从安装Python环境开始,逐步介绍变量、数据类型、控制结构、函数和模块等基本概念。通过实例演示和练习,读者将学会如何编写简单的Python程序,并了解如何解决常见的编程问题。文章最后将提供一些资源,以供进一步学习和实践。
25 1
|
15天前
|
存储 网络协议 IDE
从零起步学习Python编程
从零起步学习Python编程
|
13天前
|
机器学习/深度学习 存储 数据挖掘
Python 编程入门:理解变量、数据类型和基本运算
【10月更文挑战第43天】在编程的海洋中,Python是一艘易于驾驭的小船。本文将带你启航,探索Python编程的基础:变量的声明与使用、丰富的数据类型以及如何通过基本运算符来操作它们。我们将从浅显易懂的例子出发,逐步深入到代码示例,确保即使是零基础的读者也能跟上步伐。准备好了吗?让我们开始吧!
24 0
|
数据采集 数据挖掘 编译器
【Python 基础教程】错误与异常的处理
【Python 基础教程】错误与异常的处理
【Python 基础教程】错误与异常的处理
|
存储 缓存 安全
【python】错误和异常(第三讲)
assert,翻译过来是“断言”之意。assert 是一句等价于布尔真的判定,发生异常就意味着表达式为假。 assert 的应用情景就有点像汉语的意思一样,当程序运行到某个节点的时候,就断定某个变量的值必然是什么,或者对象必然拥有某个属性等,简单说就是断定什么东西必然是什么,如果不是,就抛出错误。......
235 0
【python】错误和异常(第三讲)
|
自然语言处理 Linux 测试技术
【python】错误和异常(第二讲)
处理多个异常,并不是因为同时报出多个异常。程序在运行中,只要遇到一个异常就会有反应,所以,每次捕获到的异常一定是一个。所谓处理多个异常的意思是可以容许捕获不同的异常,有不同的 except 子句处理。......
167 0
【python】错误和异常(第二讲)