python“with”语句,是否应使用contextlib.closing?

2024-04-27 01:15:40 发布

您现在位置:Python中文网/ 问答频道 /正文

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

这是烧瓶教程第3步(http://flask.pocoo.org/docs/tutorial/dbinit/#tutorial-dbinit)。我对第四行有点好奇。

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

当我了解到with语句时,很多文章都说它会在如下过程之后自动关闭文件(与Finally:thing.close()相同)

with open('filename','w') as f:
    f.write(someString);

即使我没有像下面那样使用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()

Tags: appdbsqlinitschemadefasconnect
2条回答

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

是的,您应该使用context.closing();您自己的版本做了完全不同的事情。

with语句让上下文管理器知道何时输入和退出代码块;在退出时,上下文管理器还被授予访问异常(如果发生异常)的权限。文件对象使用此选项在块退出时自动关闭文件。

教程中的connect_db()函数返回一个^{} connection object,它确实可以用作context manager但是,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())

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

相关问题 更多 >