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

    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语句中使用的对象。

的想法是,它可以很容易地这就需要执行一些“cleandown”代码(认为它作为一个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 - 在 '与' 语句'有一个很好的书面记录为好。

其他提示

如果你知道什么的上下文管理器是,那么你需要什么更多的了解__enter____exit__魔术方法。让我们看看一个非常简单的例子。

在这个例子中我开口的 myfile.txt的打开功能的帮助。在的try /最后块确保即使发生了意外的异常的 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) 

如果你在看代码,我没有关闭文件和不存在的尝试/终于阻止。因为<强>与语句自动关闭的 myfile.txt的即可。你甚至可以通过调用print(fp.closed)属性检查 - 返回True

这是因为,通过打开函数返回的文件中的对象(在我的例子FP)具有两个内置方法__enter____exit__。它也被称为上下文管理。 __enter__方法被称为在的块和__exit__方法被调用在端部开始。注:语句只适用于支持上下文mamangement协议,即他们有__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__方法Python文档,所以帮助别人这里是链接:

https://docs.python.org/ 2 /参考/ datamodel.html#与语句上下文经理结果 https://docs.python.org/3/reference /datamodel.html#with-statement-context-managers 结果 (细节是相同的两个版本)

  

object.__enter__(self)结果   输入与此相关的运行时环境。该with语句将这个方法的返回值绑定到语句的作为子句中指定的目标(一个或多个),如果有的话。

     

object.__exit__(self, exc_type, exc_value, traceback)结果   退出与此相关的运行时环境。参数描述导致上下文退出异常。如果上下文未经异常退出,所有三个参数将是None

     

如果一个异常被提供,并且该方法希望抑制异常(即,防止它被传播)时,它应该返回一个真值。否则,该异常会被正常退出时从该方法加工。

     

请注意__exit__()方法不应该再加注传入的异常;这是调用者的责任。

我希望的的__exit__方法参数的明确说明。这是缺乏,但我们可以推断出他们......

据推测exc_type是类的异常。

它说,你不应该再提高传入的例外。这告诉我们,其中一个参数可能是一个实际的异常情况,或者......你应该从自己的类型和值实例呢?

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

  

例如,下面的方法__exit__燕子任何类型错误,但通过让所有其他异常:

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

...如此明确value是一个例外实例。

和推测traceback是一个Python 回溯对象。

在除了上述答案举例调用顺序,一个简单的示例运行

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__

一个提醒:使用语法with myclass() as mc时,可变MC得到由__enter__()返回的值,在上述情况下None!对于这样的用途,需要定义的返回值,如:

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

尝试添加我的答案(我的学习想法):

__enter__[__exit__] 两者都是在进入和退出“的主体时调用的方法”with 语句" (公众号 343)并且两者的实现称为上下文管理器。

with语句的目的是隐藏tryfinally子句的流程控制,使代码难以理解。

with 语句的语法是:

with EXPR as VAR:
    BLOCK

翻译为(如 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 present
        BLOCK
    except:
        # The exceptional case is handled here
        exc = False
        if 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 here
    if exc:
        exit(mgr, None, None, None)

尝试一些代码:

>>> 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'

现在手动尝试(遵循翻译语法):

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

服务器端的结果和之前一样

抱歉我的英语不好和不清楚的解释,谢谢......

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top