解释Python的'__enter__'和'__exit__'
我在某人的代码中看到了这个。 这是什么意思?
def __enter__(self): return self def __exit__(self, type, value, tb): self.stream.close()
from __future__ import with_statement#for python2.5 class a(object): def __enter__(self): print 'sss' return 'sss111' def __exit__(self ,type, value, traceback): print 'ok' return False with a() as s: print s print s
使用这些神奇的方法( __enter__
, __exit__
)可以让你实现可以很容易地使用with
语句的对象。
这个想法是,它可以轻松地构build需要执行一些“清理”代码的代码(将其视为try-finally
块)。 这里有更多的解释 。
一个有用的例子可能是一个数据库连接对象(然后一旦对应的'with'语句超出了范围就自动closures连接:
class DatabaseConnection(object): def __enter__(self): # make a database connection and return it ... return self.dbconn def __exit__(self, exc_type, exc_val, exc_tb): # make sure the dbconnection gets closed self.dbconn.close() ...
如上所述,用with
语句来使用这个对象(如果你使用的是Python 2.5,你可能需要在文件顶部的from __future__ import with_statement
)。
with DatabaseConnection() as mydbconn: # do stuff
PEP343 – 'with'语句'也有很好的写法。
如果你知道上下文pipe理器是什么,那么你就不需要__enter__
理解__enter__
和__exit__
魔法了。 让我们看一个非常简单的例子。
在这个例子中,我打开myfile.txt 打开函数的帮助。 try / finally块确保即使意外的exception发生, myfile.txt也将被closures。
fp=open(r"C:\Users\SharpEl\Desktop\myfile.txt") try: for line in fp: print(line) finally: fp.close()
现在我用声明打开同一个文件:
with open(r"C:\Users\SharpEl\Desktop\myfile.txt") as fp: for line in fp: print(line)
如果你看代码,我没有closures文件,没有try / finally块。 因为用语句自动closuresmyfile.txt 。 你甚至可以通过调用print(fp.closed)
属性来检查它 – 返回True
。
这是因为open函数返回的文件对象(在我的例子中是fp)有两个内置方法__enter__
和__exit__
。 它也被称为上下文pipe理器。 在块的__exit__
调用__exit__
方法,最后调用__exit__
方法。 注意: with语句只适用于支持上下文mamangement协议的对象,即它们有__enter__
和__exit__
方法。 实现这两种方法的类被称为上下文pipe理器类。
现在让我们定义自己的上下文pipe理器类。
class Log: def __init__(self,filename): self.filename=filename self.fp=None def logging(self,text): self.fp.write(text+'\n') def __enter__(self): print("__enter__") self.fp=open(self.filename,"a+") return self def __exit__(self, exc_type, exc_val, exc_tb): print("__exit__") self.fp.close() with Log(r"C:\Users\SharpEl\Desktop\myfile.txt") as logfile: print("Main") logfile.logging("Test1") logfile.logging("Test2")
我希望现在你对__enter__
和__exit__
魔法有基本的了解。
我发现奇怪的是很难findPythonsearch__enter__
和__exit__
方法谷歌search,所以帮助这里的其他人是链接:
https://docs.python.org/2/reference/datamodel.html#with-statement-context-managers
object.__enter__(self)
input与此对象相关的运行时上下文。with
语句会将此方法的返回值绑定到语句的as子句中指定的目标(如果有)。
object.__exit__(self, exc_type, exc_value, traceback)
退出与此对象相关的运行时上下文。 参数描述导致上下文退出的exception。 如果上下文没有exception退出,则所有三个参数都是None
。如果提供了一个exception,并且该方法希望抑制该exception(即阻止它被传播),它应该返回一个真正的值。 否则,在退出此方法后,exception将被正常处理。
请注意
__exit__()
方法不应该重新传入传入的exception; 这是来电者的责任。
我希望清楚的描述__exit__
方法参数。 这是缺乏,但我们可以推断他们…
推测exc_type
是例外的类。
它说你不应该重新提出传入的例外。 这向我们表明,其中一个参数可能是一个实际的Exception实例…或者你应该从types和值中自己实例化它?
我们可以通过看这篇文章来回答:
http://effbot.org/zone/python-with-statement.htm
例如,下面的
__exit__
方法吞下任何TypeError,但通过其他所有exception:
def __exit__(self, type, value, traceback): return isinstance(value, TypeError)
…很明显, value
是一个Exception实例。
大概traceback
是一个Python追溯对象。