我在某人的代码中看到了这个。这是什么意思?

    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__神奇的方法了。让我们看一个非常简单的例子。

在这个例子中,我使用open函数打开myfile.txt文件。try/finally块确保即使出现意外异常,myfile.txt也会被关闭。

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) 

如果你看一下代码,我没有关闭文件&没有try/finally块。因为with语句会自动关闭myfile.txt。你甚至可以通过调用print(fp.closed)属性来检查它——它返回True。

这是因为open函数返回的文件对象(在我的例子中是fp)有两个内置方法__enter__和__exit__。它也被称为上下文管理器。__enter__方法在with block开始时调用,__exit__方法在with block结束时调用。

注意:with语句只适用于支持上下文管理协议的对象(即它们有__enter__和__exit__方法)。实现这两个方法的类称为上下文管理器类。

现在让我们定义自己的上下文管理器类。

 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__魔术方法有了基本的了解。

其他回答

使用这些神奇的方法(__enter__, __exit__)可以让你实现可以用with语句轻松使用的对象。

其思想是,它使构建需要执行一些“清理”代码的代码变得容易(可以将其视为一个try-finally块)。这里有更多的解释。

一个有用的例子是数据库连接对象(一旦对应的'with'语句超出范围,它就会自动关闭连接):

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”语句也有很好的写法。

如果你知道什么是上下文管理器,那么你就不需要再理解__enter__和__exit__神奇的方法了。让我们看一个非常简单的例子。

在这个例子中,我使用open函数打开myfile.txt文件。try/finally块确保即使出现意外异常,myfile.txt也会被关闭。

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) 

如果你看一下代码,我没有关闭文件&没有try/finally块。因为with语句会自动关闭myfile.txt。你甚至可以通过调用print(fp.closed)属性来检查它——它返回True。

这是因为open函数返回的文件对象(在我的例子中是fp)有两个内置方法__enter__和__exit__。它也被称为上下文管理器。__enter__方法在with block开始时调用,__exit__方法在with block结束时调用。

注意:with语句只适用于支持上下文管理协议的对象(即它们有__enter__和__exit__方法)。实现这两个方法的类称为上下文管理器类。

现在让我们定义自己的上下文管理器类。

 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__魔术方法有了基本的了解。

这被称为上下文管理器,我只是想补充一点,其他编程语言也存在类似的方法。比较它们有助于理解python中的上下文管理器。 基本上,当我们处理一些资源(文件、网络、数据库)时,上下文管理器会被使用,这些资源需要初始化,并且在某些时候需要销毁(销毁)。在Java 7及以上版本中,我们有如下形式的自动资源管理:

//Java code
try (Session session = new Session())
{
  // do stuff
}

注意,Session需要实现AutoClosable或它的(许多)子接口之一。

在c#中,我们有用于管理资源的using语句,其形式为:

//C# code
using(Session session = new Session())
{
  ... do stuff.
}

其中Session应该实现IDisposable。

在python中,我们使用的类应该实现__enter__和__exit__。所以它的形式是:

#Python code
with Session() as session:
    #do stuff

正如其他人指出的那样,您可以在所有语言中使用try/finally语句来实现相同的机制。这只是语法糖。

我发现通过谷歌搜索找到__enter__和__exit__方法的python文档非常困难,所以这里有链接来帮助其他人:

https://docs.python.org/2/reference/datamodel.html#with-statement-context-managers https://docs.python.org/3/reference/datamodel.html#with-statement-context-managers (两个版本的细节相同)

object.__enter__(自我) 输入与此对象相关的运行时上下文。with语句将该方法的返回值绑定到语句的as子句中指定的目标(如果有的话)。

对象。__exit__(self, exc_type, exc_value, traceback) 退出与此对象相关的运行时上下文。参数描述了导致退出上下文的异常。如果没有异常退出上下文,所有三个参数都将为None。

如果提供了一个异常,而该方法希望抑制该异常(即防止它被传播),它应该返回一个真值。否则,异常将在退出此方法时正常处理。

注意__exit__()方法不应该重新引发传入的异常;这是调用者的责任。

我希望清楚地描述__exit__方法参数。这是缺乏的,但我们可以推断他们…

假定exc_type是异常的类。

它说你不应该重新引发传入异常。这提示我们,其中一个参数可能是一个实际的异常实例…或者你应该自己从类型和值实例化它?

我们可以看看这篇文章来回答: http://effbot.org/zone/python-with-statement.htm

例如,下面的__exit__方法接受任何TypeError,但允许所有其他异常通过:

def __exit__(self, type, value, traceback):
    return isinstance(value, TypeError)

…所以value显然是一个Exception实例。

traceback大概是一个Python回溯对象。

注意这里还有更多的文档: https://docs.python.org/3/library/stdtypes.html#context-manager-types

...他们对__enter__和__exit__方法有稍微详细的解释。特别是__exit__应该返回一个布尔值(尽管true或falsy也可以,例如,一个隐式的None返回将给出传播异常的默认行为)。

除了上面的回答来举例调用顺序外,还有一个简单的运行示例

class MyClass:
    def __init__(self):
        print("__init__")

    def __enter__(self): 
        print("__enter__")

    def __exit__(self, type, value, traceback):
        print("__exit__")
    
    def __del__(self):
        print("__del__")
    
with MyClass(): 
    print("body")

产生输出:

__init__
__enter__
body
__exit__
__del__

提醒:当使用MyClass()语法作为my_handler时,变量my_handler将获得由__enter__()返回的值,在上述情况下为None!对于这种用途,需要定义返回值,例如:

def __enter__(self): 
    print('__enter__')
    return self