本文翻译自:Explaining Python's '__enter__' and '__exit__'

I saw this in someone's code. 我在某人的代码中看到了这个。 What does it mean? 这是什么意思?

    def __enter__(self):return selfdef __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 Falsewith a() as s:print sprint s

#1楼

参考:https://stackoom.com/question/8KDF/解释Python的-enter-和-exit


#2楼

Using these magic methods ( __enter__ , __exit__ ) allows you to implement objects which can be used easily with the with statement. 使用这些魔术方法( __enter____exit__ )可以实现可以使用with语句轻松使用的对象。

The idea is that it makes it easy to build code which needs some 'cleandown' code executed (think of it as a try-finally block). 我们的想法是,它可以轻松构建需要执行一些“清理”代码的代码(将其视为try-finally块)。 Some more explanation here . 这里有更多解释 。

A useful example could be a database connection object (which then automagically closes the connection once the corresponding 'with'-statement goes out of scope): 一个有用的例子可能是数据库连接对象(一旦相应的'with'语句超出范围,它就会自动关闭连接):

class DatabaseConnection(object):def __enter__(self):# make a database connection and return it...return self.dbconndef __exit__(self, exc_type, exc_val, exc_tb):# make sure the dbconnection gets closedself.dbconn.close()...

As explained above, use this object with the with statement (you may need to do from __future__ import with_statement at the top of the file if you're on Python 2.5). 如上所述,将此对象与with语句一起with (如果您使用的是Python 2.5,则可能需要在文件顶部使用from __future__ import with_statement )。

with DatabaseConnection() as mydbconn:# do stuff

PEP343 -- The 'with' statement' has a nice writeup as well. PEP343 - 'with'语句'也有一个很好的写法。


#3楼

If you know what context managers are then you need nothing more to understand __enter__ and __exit__ magic methods. 如果您知道上下文管理器是什么,那么您无需了解__enter____exit__魔术方法。 Lets see a very simple example. 让我们看一个非常简单的例子。

In this example I am opening myfile.txt with help of open function. 在这个例子中,我在open函数的帮助下打开 myfile.txtThe try/finally block ensures that even if an unexpected exception occurs myfile.txt will be closed. try / finally块确保即使发生意外异常, myfile.txt也将被关闭。

fp=open(r"C:\Users\SharpEl\Desktop\myfile.txt")
try:for line in fp:print(line)
finally:fp.close()

Now I am opening same file with with statement: 现在我用with语句打开同一个文件:

with open(r"C:\Users\SharpEl\Desktop\myfile.txt") as fp:for line in fp:print(line)

If you look at the code, I didn't close the file & there is no try/finally block. 如果你看代码,我没有关闭文件,没有try / finally块。 Because with statement automatically closes myfile.txt . 因为with语句会自动关闭myfile.txtYou can even check it by calling print(fp.closed) attribute -- which returns True . 你甚至可以通过调用print(fp.closed)属性来检查它 - 它返回True

This is because the file objects (fp in my example) returned by open function has two built-in methods __enter__ and __exit__ . 这是因为open函数返回的文件对象(在我的例子中为fp)有两个内置方法__enter____exit__It is also known as context manager. 它也被称为上下文管理器。 __enter__ method is called at the start of with block and __exit__ method is called at the end. __enter__方法在with的开头调用,最后调用__exit__方法。 Note: with statement only works with objects that support the context mamangement protocol ie they have __enter__ and __exit__ methods. 注意: with语句仅适用于支持上下文管理协议的对象,即它们具有__enter____exit__方法。 A class which implement both methods is known as context manager class. 实现这两种方法的类称为上下文管理器类。

Now lets define our own context manager class. 现在让我们定义自己的上下文管理器类。

 class Log:def __init__(self,filename):self.filename=filenameself.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")

I hope now you have basic understanding of both __enter__ and __exit__ magic methods. 我希望你现在对__enter____exit__魔术方法有基本的了解。


#4楼

I found it strangely difficult to locate the python docs for __enter__ and __exit__ methods by Googling, so to help others here is the link: 我发现通过Googling找到__enter____exit__方法的python文档很奇怪,所以在这里帮助其他人是链接:

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

object.__enter__(self)
Enter the runtime context related to this object. 输入与此对象相关的运行时上下文。 The with statement will bind this method's return value to the target(s) specified in the as clause of the statement, if any. with语句将此方法的返回值绑定到语句的as子句中指定的目标(如果有)。

object.__exit__(self, exc_type, exc_value, traceback)
Exit the runtime context related to this object. 退出与此对象相关的运行时上下文。 The parameters describe the exception that caused the context to be exited. 参数描述导致退出上下文的异常。 If the context was exited without an exception, all three arguments will be None . 如果在没有异常的情况下退出上下文,则所有三个参数都将为None

If an exception is supplied, and the method wishes to suppress the exception (ie, prevent it from being propagated), it should return a true value. 如果提供了异常,并且该方法希望抑制异常(即,防止它被传播),则它应该返回一个真值。 Otherwise, the exception will be processed normally upon exit from this method. 否则,在退出此方法时将正常处理异常。

Note that __exit__() methods should not reraise the passed-in exception; 请注意, __exit__()方法不应该重新传入传入的异常; this is the caller's responsibility. 这是来电者的责任。

I was hoping for a clear description of the __exit__ method arguments. 我希望明确描述__exit__方法参数。 This is lacking but we can deduce them... 这是缺乏的,但我们可以推断它们......

Presumably exc_type is the class of the exception. 推测exc_type是异常的类。

It says you should not re-raise the passed-in exception. 它说你不应该重新提高传入的异常。 This suggests to us that one of the arguments might be an actual Exception instance ...or maybe you're supposed to instantiate it yourself from the type and value? 这告诉我们其中一个参数可能是一个实际的Exception实例......或者你应该从类型和值中自己实例化它?

We can answer by looking at this article: 我们可以通过查看这篇文章来回答:
http://effbot.org/zone/python-with-statement.htm http://effbot.org/zone/python-with-statement.htm

For example, the following __exit__ method swallows any TypeError, but lets all other exceptions through: 例如,以下__exit__方法吞下任何TypeError,但允许所有其他异常通过:

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

...so clearly value is an Exception instance. ...很明显, value是一个Exception实例。

And presumably traceback is a Python traceback object. 并且可能是traceback是一个Python 回溯对象。


#5楼

In addition to the above answers to exemplify invocation order, a simple run example 除了举例说明调用顺序的上述答案之外,还有一个简单的运行示例

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")

Produces the output: 产生输出:

__init__
__enter__
body
__exit__
__del__

A reminder: when using the syntax with myclass() as mc , variable mc gets the value returned by __enter__() , in the above case None ! 提醒:当使用with myclass() as mc的语法with myclass() as mc ,变量mc获取__enter__()返回的值,在上面的例子中为None For such use, need to define return value, such as: 对于这种用法,需要定义返回值,例如:

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

#6楼

try adding my answers (my thought of learning) : 尝试添加我的答案(我的学习思路):

__enter__ and [__exit__] both are methods that are invoked on entry to and exit from the body of " the with statement " ( PEP 343 ) and implementation of both is called context manager. __enter__[__exit__]都是在进入和退出“ with语句 ”( PEP 343 )主体时调用的方法,两者的实现都称为上下文管理器。

the with statement is intend to hiding flow control of try finally clause and make the code inscrutable. with语句打算隐藏try finally子句的流控制并使代码难以理解。

the syntax of the with statement is : with语句的语法是:

with EXPR as VAR:BLOCK

which translate to (as mention in PEP 343) : 转化为(如PEP 343中所述):

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 presentBLOCKexcept:# The exceptional case is handled hereexc = Falseif 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 hereif exc:exit(mgr, None, None, None)

try some code: 尝试一些代码:

>>> import logging
>>> import socket
>>> import sys#server socket on another terminal / python interpreter
>>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> s.listen(5)
>>> s.bind((socket.gethostname(), 999))
>>> while True:
>>>    (clientsocket, addr) = s.accept()
>>>    print('get connection from %r' % addr[0])
>>>    msg = clientsocket.recv(1024)
>>>    print('received %r' % msg)
>>>    clientsocket.send(b'connected')
>>>    continue#the client side
>>> class MyConnectionManager:
>>>     def __init__(self, sock, addrs):
>>>         logging.basicConfig(level=logging.DEBUG, format='%(asctime)s \
>>>         : %(levelname)s --> %(message)s')
>>>         logging.info('Initiating My connection')
>>>         self.sock = sock
>>>         self.addrs = addrs
>>>     def __enter__(self):
>>>         try:
>>>             self.sock.connect(addrs)
>>>             logging.info('connection success')
>>>             return self.sock
>>>         except:
>>>             logging.warning('Connection refused')
>>>             raise
>>>     def __exit__(self, type, value, tb):
>>>             logging.info('CM suppress exception')
>>>             return False
>>> addrs = (socket.gethostname())
>>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> with MyConnectionManager(s, addrs) as CM:
>>>     try:
>>>         CM.send(b'establishing connection')
>>>         msg = CM.recv(1024)
>>>         print(msg)
>>>     except:
>>>         raise
#will result (client side) :
2018-12-18 14:44:05,863         : INFO --> Initiating My connection
2018-12-18 14:44:05,863         : INFO --> connection success
b'connected'
2018-12-18 14:44:05,864         : INFO --> CM suppress exception#result of server side
get connection from '127.0.0.1'
received b'establishing connection'

and now try manually (following translate syntax): 现在尝试手动(按照翻译语法):

>>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #make new socket object
>>> mgr = MyConnection(s, addrs)
2018-12-18 14:53:19,331         : INFO --> Initiating My connection
>>> ext = mgr.__exit__
>>> value = mgr.__enter__()
2018-12-18 14:55:55,491         : INFO --> connection success
>>> exc = True
>>> try:
>>>     try:
>>>         VAR = value
>>>         VAR.send(b'establishing connection')
>>>         msg = VAR.recv(1024)
>>>         print(msg)
>>>     except:
>>>         exc = False
>>>         if not ext(*sys.exc_info()):
>>>             raise
>>> finally:
>>>     if exc:
>>>         ext(None, None, None)
#the result:
b'connected'
2018-12-18 15:01:54,208         : INFO --> CM suppress exception

the result of the server side same as before 服务器端的结果与以前相同

sorry for my bad english and my unclear explanations, thank you.... 对不起我的英文不好和我不清楚的解释,谢谢....

解释Python的‘__enter __‘和‘__exit__‘相关推荐

  1. 巴斯光年python turtle绘图__附源代码

    巴斯光年python turtle绘图__附源代码 本文目录: 一.python turtle海龟绘图效果图 写在前面的题外话 二.绘图人物简介 三.代码演示方法和代码命令解释 四.怎么才能正常运行p ...

  2. 解释python脚本程序的name变量及其作用_一些概念总结

    is 与 == 的区别 Python中万物皆对象,每个对象都包含3个属性:id,type,value.1.id就是对象地址,可以通过内置函数id()查看对象引用的地址.2.type就是对象类型,可以通 ...

  3. 简学Python第二章__巧学数据结构文件操作

    Python第二章__巧学数据结构文件操作 欢迎加入Linux_Python学习群  群号:478616847 目录: 列表 元祖 索引 字典 序列 文件操作 编码与文件方法 本站开始将引入一个新的概 ...

  4. python类和对象课件_简单解释Python的类和对象

    前言: 对象是模拟真实世界,把数据和程序进行封装 . 对象 = 属性+ 方法 我们需要用类来创造一个对象,就像我们要用图纸来造房子一样.在Python中函数名是以小写字母开头 ,类名是以大写字母开头. ...

  5. python _、__和__xx__的区别

    "_"单下划线 Python中不存在真正的私有方法.为了实现类似于c++中私有方法,可以在类的方法或属性前加一个"_"单下划线,意味着该方法或属性不应该去调用, ...

  6. python中文解释-python注释中文

    广告关闭 2017年12月,云+社区对外发布,从最开始的技术博客到现在拥有多个社区产品.未来,我们一起乘风破浪,创造无限可能. 4.python代码注释最后更新于:2019-10-05 14:25:4 ...

  7. python中文解释-python是解释型语言么

    python是解释型语言么? python并非完全是解释性语言,它是有编译的,先把源码py文件编译成pyc或者pyo,然后由python的虚拟机执行,相对于py文件来说,编译成pyc和pyo本质上和p ...

  8. os.urandom(n)函数解释Python

    os.urandom(n)函数在python官方文档中做出了这样的解释 函数定位: Return a string of n random bytes suitable for cryptograph ...

  9. Python中_,__,__xx__的区别

    _xx 单下划线开头 Python中没有真正的私有属性或方法,可以在你想声明为私有的方法和属性前加上单下划线,以提示该属性和方法不应在外部调用.如果真的调用了也不会出错,但不符合规范. #! /usr ...

最新文章

  1. 温商机器人企业_7家温商企业上榜“中国企业500强”
  2. openresty配置部署
  3. 树莓派删除python2.7设置python3.5
  4. 【JDK源码分析】StringBuilder、StringBuilder、String、AbstractStringBuilder源码解析
  5. 10-1-数据库连接池
  6. Java使用正则表达式抓取日期和访问量
  7. expdp 详解及实例
  8. 致我唯一的kiyoumi
  9. 【阅读笔记】频率视角下的机器学习
  10. 你的功夫真的夠了嗎?
  11. C++使用OLE高速读写EXCEL的源码
  12. 操作系统存储管理之虚拟存储与分页式虚拟存储系统
  13. OpenCV曝光参数和快门时间的对应关系
  14. java汽车租赁系统(java租赁系统java共享汽车java汽车租借系统)java汽车租赁管理系统java自行车租赁系统共
  15. java中jsp是什么_JSP是什么?
  16. 如何在Kindle上阅读漫画书和漫画
  17. 第三方微信授权登录的iOS代码分析
  18. ubuntu下,在QT中利用科大讯飞语音库实现语音合成TTS
  19. 发言稿开场白范文_演讲稿开场白经典范文
  20. android 新开发工具,Android开发人员必备的10个开发工具

热门文章

  1. frame,iframe,frameset用法和区别
  2. 《你必须知道的.NET》,蓄势待发;博客园开发者征途,又添新作
  3. Retrofit 2.0:有史以来最大的改进
  4. Photoshop 混色模式学习
  5. 算法-----------接雨水(Java版本)
  6. Java网络编程笔记2
  7. TCP第4次挥手为何要等待2MSL才关闭?
  8. 【Android UI设计与开发】第02期:引导界面(二)使用ViewPager实现欢迎引导页面
  9. Swift 泛型函数补充
  10. (0006) iOS 开发之JavaScriptCore 实现UIWebView和HTML的交互