解释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追溯对象。