python核心编程-错误与异常

本章主题:
什么是异常
Python中的异常
探测和处理异常
上下文管理
引发异常
断言
标准异常
创建异常
相关模块

什么是异常

  • 错误

从软件方面来说,错误是语法或是逻辑上的。语法错误只是软件的结构上有错误,导致不能被解释器解释或者编译器无法编译。这些错误必须在程序执行前被纠正。
当程序的语法正确之后,剩下的就是逻辑错误了。逻辑错误可能是由于不完整或是不合法的输入所致,在其他情况下,还可能是逻辑无法生成、计算、或是输出结果需要的过程无法执行。这些错误通常被称为域错误和范围错误。
当Python检测到一个错误时,解释器会指出当前流已经无法继续执行下去。这个时候就出现异常。

  • 异常

对异常最好的描述是:它是因为程序出现了错误而在正常控制流以外采取的行为。这个行为又分为两个阶段:首先是引起异常发生的错误,然后是检测(和采取可能的措施)阶段。

python中的异常
  • NameError :尝试访问一个未申明的变量

>>> foo
Traceback (innermost last):
  File "<stdin>",line 1, in ?
NameError: name 'foo' is not defined
#NameError 表示我们访问了一个没有初始化的变量。在Python解释器的符号表没有找到那个令人讨厌的变量,我们将在后面的两章讨论名称空间,现在大家可以认为它们是连接名字和对象的“地址簿”就可以了
#任何可访问的变量必须在名称空间里列出,访问变量需要由解释器进行搜索,如果请求的名字没有在任何名称空间里找到,那么将会生成一个NameError异常
  • ZeroDivisionError : 除数为零
>>> 1/0
Traceback (inner last):
  File"<stdin>",line 1,in ?
ZeroDivisionError: integer division or modulo by zero

#任何数值被零除都会导致一个ZeroDivisionError异常
  • SyntaxError: Python 解释器语法错误
>>> for 
    File "<string>", line 1
        for 
            ^
SyntaxError: invalid syntax
#SyntaxError 异常时唯一不是在运行时发生的异常。它代表Python
代码中有一个不正确的结构,在它改正之前程序是无法执行的。这些错误一般都是在编译时发生,Python解释器无法把你脚本转化为python字节码。也有可能是你导入了一个有缺陷的模块。
  • IndexError : 请求的索引超出序列范围
>>> alist = []
>>> alist[0]
Traceback (innermost last):
    File "<stdin>", line 1,in ?
IndexError: last index out of range
#IndexError 在你尝试使用一个超出范围的值索引序列引发。
  • KeyError :请求一个不存在的字典的关键字
>>> aDict = {'host': 'earth','port':  80}
>>> print aDict['server']
Traceback (innermost last):
    File "<stdin>", line 1, in ?
KeyError: server

#映射对象,例如字典,是依靠关键字(key)访问数据的,如果使用了错误的或者是不存在的键请求字典会引发一个KeyError异常。
  • IOError : 输入/输出错误
>>> f = open ("blah")
Traceback (innermost last):
    File "<stdin>",line 1, in ?
IOError: [Errno 2] No such file or directory: 'blah'

#类似尝试打开一个不存在的磁盘文件一类的操作会引起一个操作系统输入/输出(I/O)错误。任何类型的I/O错误都会引发IOError异常
  • AttributeError : 尝试访问未知的对象属性
>>> class myClass(object) :
...     pass
...
>>> myInst = myClass()
>>> myInst.bar = 'spam'
>>> myInst.bar
'spam'
>>> myInst.foo
Traceback (innermost last):
    File "<stdin>", line 1, in ?
AttributeError foo

#在这个例子里,我们在myInst.bar存储了一个值,也就是实例myInst的bar属性,属性被定义后,我们可以使用梳洗的点属性操作符访问它,但如果是没有定义属性,例如我们访问foo属性,将导致一个AttributeError异常。
检测和处理异常
异常可以通过try语句来检测。任何在try语句块里的代码都会被检测,检查有无异常发生。
try语句有二种形式: try-except和try-finally 这两个语句是互斥的,也就是说你只能使用其中的一种。一个try语句可以对应一个或者多个except子句,但只能对应一个finally子句,或者是一个try-except-finally复合语句。

try-except语句
try:
    try_suite #监控这里的异常
except Exception[,reason]:
    except_suite #异常处理代码

>>> try:
...    f = open ('blah','r')
... except IOError,e:
...    print 'could not open file:',e
...
cloud not open file: [Errno 2] No such file or directory
处理多个异常的except语句
#我们还可以在一个except子句里处理多个异常。except语句在处理多个异常要求异常被放在一个元祖里:
except (Exception1,Exception2)[,reason]:
    suite_for_Exception1_and_Exception2

def safe_float(object):
    try:
        retval = float(object)
    except (ValueError,TypeError):
        retval = 'argument must be a number or numberic string'
    return retval
捕获所有异常
#way1
#
try:
    :
except Exception, e:
     #error occurred,log 'e',etc.

#way2
#
try:
    :
except:
    #error occurred,etc

#关于捕获所有异常,你应当知道有些异常不是由错误条件引起的,它们是SystemExit和KeyboardInterupt。
#SystemExit是由于当前Python应用程序需要退出
#KeyboardInterrupt是代表用户按下了Ctrl+C,想要退出Python。在真正需要的时候,这些异常却会被异常捕获。


异常被迁移到新式类(new-style class)启用了一个新的“所有异常之母”,这个类叫做 BaseException,异常的继承结构有了少许的调整,为了让人们摆脱不得不除创建两个处理器惯用法。

- BaseException
    | - KeyboardInterrupt
    | - SystemExit
    | - Exception
        | - (all other current bulit-in exception) 所有内建异常

try:
    :
except Exception, e:
     #handle real errors

#如果你确实要捕获所有异常,那么你需要使用新的 BaseException:
try:
    :
except BaseException, e:
     #handle all errors

异常参数

异常也可以有参数,异常引发后它会被传递给异常处理器。当异常被引发后参数是作为附加帮助信息传递给异常处理器的。虽然异常原因是可选的,但标准内建异常提供至少一个参数,指示异常原因的一个字符串。
异常的参数可以在处理器里忽略,但是Python提供了保存这个值得语法。我们已经在上边接触到相关内容:要想访问提供的异常原因,你必须保留一个变量来保存这个参数。把这个参数放在except语句后,接在要处理的异常后面。except语句的这个语法可以被扩展为:

# single exception
except Exception[,reason]:
    suite_for_Exception_with_Argument

# multiple exception
except (Exception1,Exception2,...,ExceptionN)[,reason]:
    suite_for_Exception1_to_ExceptionN_with_Argument

#reason将会是一个包含来自导致异常的代码的诊断信息的类实例。异常参数自身会组织一个元组,并存储为类实例(异常类的实例)的属性

无论reason只包含一个字符串或是由错误编号和字符串组成的元组,调用str(reason)总会返回一个良好可读的错误原因。不要忘记reason是一个类实例——这样做你其实是调用类的特殊方法str()

信用卡交易系统(cardrun.py)
#!/usr/bin/env python

def safe_float(obj):
    'safe version if float()'
    try:
        retval = float(obj)
    except (ValueError,TypeError), diag:
        retval = str(diag)
    return retval

def main():
    'handle 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('account 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()

else 子句

我们已经看过else语句段配合其他python语句,比如条件和循环。至于try-except语句段,它的功能和你所见过的其他else没有太多的不同: 在try范围中没有异常被检测到时,执行else子句

import 3rd_party_module
log = open('logfile','w')
try:
    3rd_party_module.function()
except:
    log.write("*** caught exception in module \n")
else:
    log.write("*** no exceptions caught\n")

log.close()
finally 子句

finally 子句是无论异常是否发生,是否捕捉都会执行的一段代码
下面是try-except-else-finally的语法实例:

try:
    A
except MyException:
    B
else:
    C
finally:
    D

#无论如何,你都可以有不止一个的except子句,但最少有一个except语句,而else和finally都是可选的。无论异常发生在A、B或C都 将执行finally块。
通过try-finally来实现关闭文件而无论错误是否发生
#方式1
try:
    try:
        ccfile = open('carddata.txt')
        txns = ccfile.readlines()
    except IOError:
        log.write('no txns this month\n')
finally:
    ccfile.close()

#方式2
try:
    try:
        ccfile = open('carddata.txt')
        txns = ccfile.readlines()
    finally:
        ccfile.close()
except IOError:
    log.write('no txns this month\n')

上下文管理
  • with语句
    类似于 try-except-finally,with语句也是用来简化代码的,这与try-except和try-finally所想达到的目的前呼后应。try-except和try-finally的一种特定的配合用法是保证共享资源的唯一分配,并在任务结束后释放它。比如文件(数据、日志、数据库等等)、线程资源、简单同步、数据库连接,等等。
    然而,with语句的目的在于从流程图中把try、except、finally关键字和资源分配释放相关代码统统去掉,而不是像try-except-finally那样仅仅简化代码使之易用
#with语法的基本语法如下:
with context_expr [as var]:
    with_suite

创建异常(myexc.py)
#!/usr/bin/env python
#

import os
import socket
import errno
import types
import 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(myarg)

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 'rmx':
            if os.access(file, permd[eachPerm])
                perms += eachPerm
            else:
                perm += '-'
        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], perms)
        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 = (error.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 = 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 = open(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()







最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容

  • 一、简介 Python最强大的结构之一就是它的异常处理能力,所有的标准异常都使用类来实现,都是基类Exceptio...
    随风化作雨阅读 3,061评论 0 1
  • Python异常处理 异常概念: 异常:就是不正常的情况,程序开发过程中错误和BUG都是补充正常的情况 异常发生的...
    youngkun阅读 919评论 0 4
  • 1.什么是异常? 异常即是一个事件,该事件会在程序执行过程中发生,影响了程序的正常执行。一般情况下,Python无...
    岁月神偷_bde8阅读 270评论 0 0
  • 王若智上小学二年级的时候。 一天,他在放学回家的路上,看到一个卖过期方便面的男人,那个男人对王若智说:“小胖子,快...
    1019d835891a阅读 594评论 0 2
  • 开着? 聚焦,如闪电,光芒万丈。 美丽如碎末的云朵, 沉淀厚重碧薄蓝天。 念念不忘的褪色的记忆, 芥末黄般的魔幻,...
    李恩亿的书屋阅读 156评论 1 2