python'with'语句,我应该使用contextlib.closing吗?

su7*_*u7k 17 python with-statement contextmanager

from contextlib import closing

def init_db():
    with closing(connect_db()) as db:
        with app.open_resource('schema.sql') as f:
            db.cursor().executescript(f.read())
        db.commit()
Run Code Online (Sandbox Code Playgroud)

这是来自烧瓶教程第3步(http://flask.pocoo.org/docs/tutorial/dbinit/#tutorial-dbinit).我对第4行感到好奇.

我必须导入并使用'contextlib.closing()'方法吗?

当我语句学习,很多文章说它会在下面的过程之后自动关闭文件.(与Last:thing.close()相同)

with open('filename','w') as f:
    f.write(someString);
Run Code Online (Sandbox Code Playgroud)

即使我不使用下面的contextlib.closing(),有什么区别?它来自2.7.6版本,谢谢.

def init_db():
    with connect_db() as db:
        with app.open_resource('schema.sql') as f:
            db.cursor().executescript(f.read())
        db.commit()
Run Code Online (Sandbox Code Playgroud)

Mar*_*ers 19

是的,你应该使用context.closing(); 你自己的版本完全不同.

with语句允许上下文管理器知道何时输入和退出代码块; 退出时,如果发生异常,则还可以访问上下文管理器.文件对象使用此选项在退出块时自动关闭文件.

connect_db()教程中的函数返回一个sqlit3连接对象,该对象确实可以用作上下文管理器.但是,该connection.__exit__()方法不会关闭连接,它会在成功完成时提交事务,或者在发生异常时中止事务.

contextlib.closing()另一方面上下文管理器,调用connection.close()的连接方法.这是完全不同的东西.

所以,你的第二个片段可能有效,但做了不同的事情.教程代码关闭连接,您的版本提交事务.您已经在调用db.commit(),因此如果没有引发异常,操作实际上是多余的.

您可以再次使用连接作为上下文管理器来实现自动事务处理行为:

def init_db():
    with closing(connect_db()) as db:
        with app.open_resource('schema.sql') as f, db:
            db.cursor().executescript(f.read())
Run Code Online (Sandbox Code Playgroud)

请注意, db第二with行,确保db.__exit__()在块退出时调用该方法.

  • 所以 `closure()` 上下文管理器 _only_ 调用 `close()` 而不会在块的末尾调用 `__enter__()` 或 `__exit__()`(即使对象本身是上下文管理器)?这是完全有道理的 - 感谢您花时间回复对这样一个旧帖子的评论。 (3认同)
  • @DavidBarker:`with closing(connect_db())作为db`做两件事:它创建一个上下文管理器,在退出时调用`connect_db()`结果上的`close()`,*和*它返回同一个对象从`cm .__输入__()`方法,所以`with`将其分配给名称`db`.现在,那个对象*本身*也是*一个上下文管理器,所以在第二个`with`中我们确保`with`调用`db .__进入__()`和`db .__退出__()`,因为那些控制着交易. (2认同)

sme*_*eso 6

该语句所做的唯一事情是在进入块之前with调用方法,在退出块之前调用方法。如果未定义这些方法,则该语句将无法按您的预期工作。我不知道 的返回类型是什么,但我猜它可能是来自不同第三方库的许多不同的东西。因此,您的代码可能会在许多(所有?)情况下工作,但您永远不知道.__enter____exit__withconnect_dbclosingconnect_db