我在某人的代码中看到了这个。这是什么意思?
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
除了上面的回答来举例调用顺序外,还有一个简单的运行示例
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
当执行进入with语句的上下文,并且是时候获取资源时,Python调用__enter__。当执行再次离开上下文时,Python调用__exit__来释放资源
让我们考虑一下上下文管理器和Python中的“with”语句。Context Manager是一个简单的“协议”(或接口),您的对象需要遵循该协议,以便与with语句一起使用。基本上,如果你想让一个对象发挥上下文管理器的作用,你所需要做的就是给它添加enter和exit方法。Python将在资源管理周期的适当时间调用这两个方法。
让我们看看实际情况是怎样的。下面是open()上下文管理器的简单实现:
class ManagedFile:
def __init__(self, name):
self.name = name
def __enter__(self):
self.file = open(self.name, 'w')
return self.file
def __exit__(self, exc_type, exc_val, exc_tb):
if self.file:
self.file.close()
我们的ManagedFile类遵循上下文管理器协议,现在支持with语句。
>>> with ManagedFile('hello.txt') as f:
... f.write('hello, world!')
... f.write('bye now')`enter code here`
当执行进入with语句的上下文,并且是时候获取资源时,Python调用enter。当执行再次离开上下文时,Python调用exit释放资源。
在Python中,编写基于类的上下文管理器并不是支持with语句的唯一方法。标准库中的contextlib实用程序模块提供了更多构建在基本上下文管理器协议之上的抽象。如果您的用例与contextlib提供的相匹配,这将使您的工作更加轻松。
除了上面的回答来举例调用顺序外,还有一个简单的运行示例
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
使用这些神奇的方法(__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”语句也有很好的写法。
这被称为上下文管理器,我只是想补充一点,其他编程语言也存在类似的方法。比较它们有助于理解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__神奇的方法了。让我们看一个非常简单的例子。
在这个例子中,我使用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__魔术方法有了基本的了解。