是否可以使用contextlib.closing()来调用任意清理方法而不是.close()

时间:2013-09-13 19:58:49

标签: python with-statement

我在python中使用with statementPEP 343)遇到了一些问题,以便在上下文后自动管理资源清理。特别是,with statement始终假定资源清理方法为.close()。 I.E.在下面的代码块中,browser.close()在执行超出上下文时自动被调用,但是,browser.close()不是正确的清理,因为它只关闭当前窗口而不是整个浏览器。它应该做的是致电browser.quit()

with contextlib.closing(webdriver.Firefox()) as browser:
    # do something with browser
# at this point browser.close() has been called.

不幸的是,contextlib.closing没有提供一种方法来自定义要调用的清理方法名称,如明显所见here

 def __exit__(self, *exc_info):
      self.thing.close()

但是,我注意到有一个参数exec_info,但没有在该特定方法中使用。谁知道为什么?

更大的问题是,如标题所示,如果可能的话,如何使用self.thing来调用任意清理方法?如果没有,最好的解决方法是什么?我应该退回使用try...finally吗?

2 个答案:

答案 0 :(得分:9)

嗯,这是python,您可以根据closing创建自己的contextlib.closing课程并覆盖__exit__()方法:

import contextlib
from selenium import webdriver

class closing(contextlib.closing):
    def __exit__(self, *exc_info):
        self.thing.quit()


with closing(webdriver.Firefox()) as browser:
    browser.get('http://stackoverflow.com')

仅供参考,有人建议将webdriver作为上下文管理器,但由于won't fix是关闭浏览器的正确方法,因此它已关闭quit(),应该调用它明确地,请参阅Make webdriver a context manager [python bindings]

答案 1 :(得分:4)

除了alecxe的答案,这是完全有效的,你也可以做这样的事情:

webdriver.Firefox.close = webdriver.Firefox.quit

现在close方法存在且与quit方法相同。

或者更好:

from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver
RemoteWebDriver.close = lambda self: self.quit()

这会修补基类以添加调用当前实例的close()的{​​{1}}方法,因此它将适用于所有驱动程序。 (第一个只是修补Firefox驱动程序。)quit()是必要的,因为基类上的lambda方法在许多(所有?)驱动程序上被覆盖,因此将quit()指向基类上的close将调用基类的方法,而不是实际使用的类中的方法。

无论哪种方式,该类现在非常适合与quitclosing()语句一起使用。