码迷,mamicode.com
首页 > 编程语言 > 详细

python中的__enter__ __exit__

时间:2018-09-18 00:31:15      阅读:262      评论:0      收藏:0      [点我收藏+]

标签:man   line   sys   The   eps   www   obj   www.   使用   

我们前面文章介绍了迭代器和可迭代对象,这次介绍python的上下文管理。在python中实现了__enter__和__exit__方法,即支持上下文管理器协议。上下文管理器就是支持上下文管理器协议的对象,它是为了with而生。当with语句在开始运行时,会在上下文管理器对象上调用 __enter__ 方法。with语句运行结束后,会在上下文管理器对象上调用 __exit__ 方法

with的语法:

with EXPR as VAR:
BLOCK


这是上面语法的伪代码:

mgr = (EXPR)   
exit = type(mgr).__exit__  # Not calling it yet
value = type(mgr).__enter__(mgr)    
exc = True     
try:
    try:
        VAR = value  # Only if "as VAR" is present
        BLOCK
    except:
        # The exceptional case is handled here
        exc = False
        if not exit(mgr, *sys.exc_info()):
            raise
        # The exception is swallowed if exit() returns true
finally:
    # The normal and non-local-goto cases are handled here
    if exc:
        exit(mgr, None, None, None)


1、生成上下文管理器mgr
2、如果没有发现__exit__, __enter__两个方法,解释器会抛出AttributeError异常
3、调用上下文管理器的 __enter__() 方法
4、如果语法里的as VAR没有写,那么 伪代码里的 VAR= 这部分也会同样被忽略
5、如果BLOCK中的代码正常结束,或者是通过break, continue ,return 来结束,__exit__()会使用三个None的参数来返回
6、如果执行过程中出现异常,则使用 sys.exc_info的异常信息为参数调用 __exit__(exc_type, exc_value, exc_traceback)


之前我们对文件的操作是这样的:

try:
    f = open(filename)
except:
    print("Unexpected error:", sys.exc_info()[0])
else:
    print(f.readlines())
    f.close()


现在有了with语句可以使代码更加简洁,减少编码量,下面的语句会在执行完后自动关闭文件(即使出现异常也会)。:

with open(example.info, r) as f:
    print(f.readlines())


一个例子:

class TmpTest:
    def __init__(self,filename):
        self.filename=filename
    def __enter__(self):
        self.f = open(self.filename, r)
       # return self.f
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.f.close()

test=TmpTest(file)

with test as t:
    print (test result: {}.format(t))

返回:

test result: None


这个例子里面__enter__没有返回,所以with语句里的"as t"到的是None,修改一下上面的例子:

class TmpTest:
    def __init__(self,filename):
        self.filename=filename
    def __enter__(self):
        self.f = open(self.filename, r)
        return self.f
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.f.close()

test=TmpTest(file)

with test as t:
    print (test result: {}.format(t))

返回:

test result: <_io.TextIOWrapper name=file mode=r encoding=cp936>

 
如果在__init__或者__enter__中抛出异常,则不会进入到__exit__中:

class TmpTest:
    def __init__(self,filename):
        self.filename=filename
        print("__init__")
        raise ImportError
    def __enter__(self):
        self.f = open(self.filename, r)
        print("__enter__")
        return self.f
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("__exit__")
        self.f.close()

test=TmpTest(file)
with test as t:
    print (test result: {}.format(t))


返回:

__init__
Traceback (most recent call last):
  File "D:/pythonScript/leetcode/leetcode.py", line 14, in <module>
    test=TmpTest(file)
  File "D:/pythonScript/leetcode/leetcode.py", line 5, in __init__
    raise ImportError
ImportError


如果在__exit__中返回True,则不会产生异常:

class TmpTest:
    def __init__(self,filename):
        self.filename=filename
        print("__init__")

    def __enter__(self):
        self.f = open(self.filename, r)
        print("__enter__")
        return self.f

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("__exit__ {} ".format(exc_type))
        self.f.close()
        return True

test=TmpTest(file)
with test as t:
    print (test result: {}.format(t))
    raise ImportError
print("no error")

返回:

__init__
__enter__
test result: <_io.TextIOWrapper name=file mode=r encoding=cp936>
__exit__ <class ImportError>
no error



参考: https://python3-cookbook.readthedocs.io/zh_CN/latest/c08/p03_make_objects_support_context_management_protocol.html?highlight=with
        https://docs.python.org/3/library/stdtypes.html#typecontextmanager
        https://www.python.org/dev/peps/pep-0343/

python中的__enter__ __exit__

标签:man   line   sys   The   eps   www   obj   www.   使用   

原文地址:https://www.cnblogs.com/flashBoxer/p/9664813.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!