2015-12-02 113 views
-1

我打开上初始化一个套接字连接类,并且可以发送和接收某些消息来回对手。我使用with语句创建对象的一个​​实例。在我的课堂上,如果我在套接字上收到某些消息,我想明确关闭连接,并退出with声明。呼叫`with`的__exit__明确和退出

我试图这样做,通过显式调用self.\__exit__(None, None, None)

def __exit__(self, type, value, traceback): 
    print 'Closing Connection' 
    self.logout() 
    self.conn.close() 
    sys.exit(1) 

不过,我发现,我收到Closing Connection消息发回的两倍,并运行到,因为在第二次调用问题,不再有一个关闭的连接。检查代码时,我排除了我明确致电self.__exit__(None, None, None)的所有其他实例。这是怎么回事?是sys.exit(1)不足以防止垃圾再次收集with(虽然从我读过,这似乎是最“批准”的方式来做到这一点)?如何防止with声明致电self.__exit__(None, None, None)。任何帮助,或在正确的方向点,将不胜感激!

+3

的'__exit__'方法当控制流离开'with'语句时总是被调用,不管这种情况如何。你不应该明确地调用它。如果你重构你的代码,这样会更好,所以你不需要这样做。 –

+0

另外,在'__exit__'函数中有'sys.exit(1)'是不好的形式。 '__exit__'函数只能抑制异常或允许它们传递;他们不应该退出程序,因为它们只是用于清理或资源管理。它隐藏了程序逻辑并使你的代码难以阅读。使用'语句从'顶级'''''sys.exit(1)'运行'''''''''''''''''因此很明显你正在退出并显示一个错误值。 – eestrada

+0

不要显式调用__exit()__',那么没有问题。你可以从上下文管理器内部返回,或者你可以结束:这应该如何调用__exit()__'。 – msw

回答

0

一旦您在with声明中,唯一不带运行__exit__的方法是使用os._exit;那很糟。相反,如果您需要这种行为,请明确从调用__enter__开始。或者改变你的班级,以确保它在两次被打电话时不会两次清理,就像@Kay在他的回答中所建议的那样。或者说,作为@IsmailBadawi表明在他的评论,重构你的代码,所以你并不需要显式调用__exit__

+0

当你说“明确地通过调用'__enter_'开始时,”你的意思是不使用'with'语句吗?所以,创建对象。然后调用'obj .__输入__()'? –

+0

@AmyD:是的,这确实是我明确调用'__enter__'的意思。但是,这不是你通常应该做的事情。我做过的唯一一次是在单元测试中作为'setUp' /'tearDown'的一部分(甚至在没有其他选项的情况下也是如此)。否则,让'with'语句为你调用'__enter__'和'__exit__'函数做好工作。所有你需要担心的是你的'__exit__'函数如何处理异常,如果它甚至需要这样做的话。 – eestrada

0

只需记住,如果你已经关闭了连接/日志/东西:

class MyContext(object): 
    def __init__(self): 
     self.__already_closed = False 

    .... 

    def close(self): 
     if not self.__already_closed: 
      self.__already_closed = True 
      self.logout() 
      self.conn.close() 

    def __exit__(...): 
     self.close() 

甚至增加了“请不要清除”的方法:

def do_not_cleanup(self): 
     self.__already_closed = True