python-自定义异常,with用法

Posted 夏晓旭

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python-自定义异常,with用法相关的知识,希望对你有一定的参考价值。

抛出异常

#coding=utf-8

 

def  exceptionTest(num):

    if num<0:

        print "if num<0"

        raise Exception("Invalid num")

 

    else:

        print num

    if num == 0:

        raise ZeroDivisionError("interger division or modulo by zero")

 

print exceptionTest(-43)

 

c:\Python27\Scripts>python task_test.py

if num<0

Traceback (most recent call last):

  File "task_test.py", line 14, in <module>

    print exceptionTest(-43)

  File "task_test.py", line 7, in exceptionTest

    raise Exception("Invalid num")

Exception: Invalid num

 

 

 

#coding=utf-8

 

def  exceptionTest(num):

    if num<0:

        print "if num<0"

        raise Exception("Invalid num")

 

    else:

        print num

    if num == 0:

        raise ZeroDivisionError("interger division or modulo by zero")

    return ""

 

print exceptionTest(4)

 

 

c:\Python27\Scripts>python task_test.py

4

 

 

#coding=utf-8

 

def  exceptionTest(num):

    if num<0:

        print "if num<0"

        raise Exception("Invalid num")

 

    else:

        print num

    if num == 0:

        raise ZeroDivisionError("interger division or modulo by zero")

    return ""

 

print exceptionTest(0)

c:\Python27\Scripts>python task_test.py

0

Traceback (most recent call last):

  File "task_test.py", line 14, in <module>

    print exceptionTest(0)

  File "task_test.py", line 11, in exceptionTest

    raise ZeroDivisionError("interger division or modulo by zero")

ZeroDivisionError: interger division or modulo by zero

 

 

 

自定义异常

通过创建一个新的异常类,程序可以创建它们自己特定的异常。自定义异常都需要继承异常基类(Exception类),当然也可以继承具体的异常类(比如RuntimeError),通过直接或间接的方式。

#coding=utf-8

 

class Neterror(RuntimeError):

    def __init__(self,value):#重写默认的__ini__()方法

        self.value=value

 

#触发自定义的异常

try:

    raise Neterror("Bad hostname")

except Neterror,e:

    print "My exception occurred,value:",e.value

 

c:\Python27\Scripts>python task_test.py

My exception occurred,value: Bad hostna

 

#coding=utf-8

class ShortInputException(Exception):

    ‘‘‘ A user-defined exception class.‘‘‘

    def __init__(self,length,atleast):

        Exception.__init__(self)

        self.length = length

        self.atleast = atleast

try:

    s= raw_input(‘Enter something-->‘)

    if len(s)<3:

        #如果输入的内容长度小于3,触发异常

        raise ShortInputException(len(s),3)

except EOFError:

    print ‘\nWhy did you do an EOF on me?‘

except ShortInputException,x:

    print "shortInputException:The input was of length %d,\

    was excepting at least %d"%(x.length,x.atleast)

else:

    print "No exception was raised"

c:\Python27\Scripts>python task_test.py

Enter something-->234s

No exception was raised

 

c:\Python27\Scripts>python task_test.py

Enter something-->3e3

No exception was raised

 

c:\Python27\Scripts>python task_test.py

Enter something-->w

shortInputException:The input was of length 1,    was excepting at least 3

 

c:\Python27\Scripts>python task_test.py

Enter something-->

shortInputException:The input was of length 0,    was excepting at least 3

 

异常抛出机制:

1、如果在运行时发生异常,解释器会查找相应的处理语句(称为handler)。

2、要是在当前函数里没有找到的话,它会将异常传递给上层的调用函数,看看 那里能不能处理。

3、如果在最外层(全局“main”)还是没有找到的话,解释器就会退出,同时打印出traceback以便让用户找到错误产生的原因。

注意:

虽然大多数错误会导致异常,但一个异常不一定代表错误,有时候它们只是一个警告,有时候它们可能是一个终止信号,比如退出循环等

 

标准异常说明

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

所有的标准/内建异常都是从根异常派生的。目前,有3 个直接从BaseException 派生的异常子类:SystemExit,KeyboardInterrupt 和Exception。其他的所有的内建异常都是Exception 的子类。

Python2.5开始,所有的异常的都是BaseException 的子类。

 

 

With介绍:

with是从Python2.5引入的一个新的语法,它是一种上下文管理协议,目的在于从流程图中把 try,except 和finally 关键字和资源分配释放相关

代码统统去掉,简化try….except….finlally的处理流程。with通过__enter__方法初始化,然后在__exit__中做善后以及处理异常。所以使用with处理的对象必须有__enter__()和__exit__()这两个方法。其中__enter__()方法在语句体(with语句包裹起来的代码块)执行之前进入运行,__exit__()方法在语句体执行完毕退出后运行。

with 语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭、线程中锁的自动获取和释放等。

 

 

With语句的基本语法格式如下

with expression [as target]:

with_body

参数说明:

expression:是一个需要执行的表达式;

target:是一个变量或者元组,存储的是expression表达式执行返回的结果, 可选参数。

#coding=utf-8

with open("d:\\a.txt",‘r‘) as fp:

    print fp.read()

   

c:\Python27\Scripts>python task_test.py

sdfsdfsdfsdf1

 

with语句的工作原理:

紧跟with后面的语句会被求值,返回对象的__enter__()方法被调用,这个方法的返回值将被赋值给as关键字后面的变量,当with后面的代码块全部被执行完之后,将调用前面返回对象的__exit__()方法。

 

 

从前面我们知道,with语句最关键的地方在于被求值对象必须有__enter__()和__exit__()这两个方法,那我们就可以通过自己实现这两方法来自定义with语句处理异常。

 

#coding=utf-8

 

class opened(object):

    def __init__(self,filename):

        self.handle=open(filename)

        print "Resource:%s" %filename

    def __enter__(self):

        print "[Enter%s]:Allocate resource." %self.handle

        return self.handle#可以返回不同的对象

    def __exit__(self,exc_type,exc_value,exc_trackback):

        print "[Exit%s]:Free resource." %self.handle

        if exc_trackback is None:

            print "[Exit%s]:Exited without exception." %self.handle

            self.handle.close()

        else:

            print "[Exit %s]: Exited with exception raised." %self.handle

        return False#可以省略,缺省的None也是被看作是False

 

with opened("d:\\a.txt") as fp:

    for line in fp.readlines():

        print line

c:\Python27\Scripts>python task_test.py

Resource:d:\a.txt

[Enter<open file ‘d:\\a.txt‘, mode ‘r‘ at 0x0000000002BC7150>]:Allocate resource.

sdfsdfsdfsdf1

[Exit<open file ‘d:\\a.txt‘, mode ‘r‘ at 0x0000000002BC7150>]:Free resource.

[Exit<open file ‘d:\\a.txt‘, mode ‘r‘ at 0x0000000002BC7150>]:Exited without exception.

 

示例代码说明:

opened中的__enter__() 返回的是自身的引用,这个引用可以赋值给 as 子句中的fp变量;返回值的类型可以根据实际需要设置为不同的类型,不必是上下文管理器对象本身。

__exit__() 方法中对变量exc_trackback进行检测,如果不为 None,表示发生了异常,返回 False 表示需要由外部代码逻辑对异常进行处理;如果没有发生异常,缺省的返回值为 None,在布尔环境中也是被看做 False,但是由于没有异常发生,__exit__() 的三个参数都为 None,上下文管理代码可以检测这种情况,做正常处理。__exit__()方法的3个参数,分别代表异常的类型、值、以及堆栈信息。

 

命名空间

Random是命名空间

导入ramdom命名空间里的randint函数

#encoding=utf-8

 

>>> from random import randint

>>> print randint(10,20)

18

 

一起引入两个

>>> from random import randint,choice

>>> print randint(10,20)

11

>>> print choice([1,2,3,4])

3

>>> 

 

直接用*,引入所有函数,但是坏处是如果本地有一个自定义的函数与命名空间里的函数同名,命名空间里的该函数会被覆盖

 

>>> from random import *

>>> print randint(10,20)

14

>>> print choice([1,2,3,4])

4

>>> 

 

覆盖例子:

#coding=utf-8

 

from random import *

 

def randint():

    return 1

 

print randint(1,20)

 

c:\Python27\Scripts>python task_test.py

Traceback (most recent call last):

  File "task_test.py", line 8, in <module>

    print randint(1,20)

TypeError: randint() takes no arguments (2 given)

 

练习:
生成一个模块a.py,里面定义一个变量c=100,定义一个函数def add(a,b) 在b.py中通过import a 和from a import *的两种方法来引入使用c变量和add函数

a.py:

import b

c=100

def add(a,b):

    return a+b

 

b.py:

import a

 

print a.c

print a.add(1,2)

 

c:\Python27\Scripts>python task_test.py

100

3

 

 

b.py:

#coding=utf-8

 

from a import *

 

print c

print add(1,2)

c:\Python27\Scripts>python task_test.py

100

3

 

如果一个py文件中有if __name__ == ‘__main__‘:,只有在运行该文件时才会执行,该文件在别文件中引用,不会被执行

a.py:

#encoding=utf-8

 

c=100

 

def add(a,b):

    return a+b

 

if __name__==‘__main__‘:

    print c

    print add(10,20)

 

c:\Python27\Scripts>python a.py

100

30

 

b.py:

#coding=utf-8

 

from a import *

 

print c+add(1,2)

 

c:\Python27\Scripts>python task_test.py

103

没有显示a.pyif __name__==’__main__’:下边的代码

 

在b.py中import a, 则a.py中的代码会都执行一遍

 

import a

reload(a)

 

reload后会再执行一遍a中的代码

 

如果import a两次,则只执行一遍a中的代码

 

 

Import a

Import a

 

 

a.py:

#encoding=utf-8

 

c=100

 

def add(a,b):

    return a+b

 

 

print "import a, codes in a will run"

 

if __name__==‘__main__‘:

    print c

print add(10,20)

 

b.py:

 

#coding=utf-8

 

from a import *

 

c:\Python27\Scripts>python task_test.py

import a, codes in a will run

 

b.py:import 两遍

#coding=utf-8

 

from a import *

from a import *

c:\Python27\Scripts>python task_test.py

import a, codes in a will run

只执行一次


以上是关于python-自定义异常,with用法的主要内容,如果未能解决你的问题,请参考以下文章

python自定义异常和主动抛出异常

python自定义异常,使用raise引发异常

python自定义异常

python 异常继承关系及自定义异常的实现

Python自定义异常及抛出异常

Python异常处理和with语句