4

我是 Python 新手。在一个连接mysql并获取数据的教程中,我看到了该with语句。我读过它,它与try-finally块有关。但我找不到一个我能理解的更简单的解释。

4

3 回答 3

10

with语句打开一个资源并保证在块完成时该资源将被关闭with,无论块如何完成。考虑一个文件:

with open('/etc/passwd', 'r') as f:
    print f.readlines()

print "file is now closed!"

该文件保证在块的末尾关闭 - 即使您有return, 即使您引发异常。

为了with做出这种保证,表达式(open()在示例中)必须是上下文管理器。好消息是许多 Python 表达式都是上下文管理器,但不是全部。

根据我发现的教程MySQLdb.connect()实际上是一个上下文管理器。

这段代码:

conn = MySQLdb.connect(...)
with conn:
    cur = conn.cursor()
    cur.do_this()
    cur.do_that()

将作为单个事务提交或回滚命令序列。这意味着您不必太担心异常或其他不寻常的代码路径——无论您如何离开代码块,事务都会得到处理。

于 2013-09-13T04:05:17.040 回答
4

从根本上说,它是一个对象,它使用在入口和出口时调用的自定义逻辑划分代码块,并且可以在其构造中接受参数。您可以使用类定义自定义上下文管理器:

class ContextManager(object):

    def __init__(self, args):
        pass

    def __enter__(self):
        # Entrance logic here, called before entry of with block
        pass

    def __exit__(self, exception_type, exception_val, trace):
        # Exit logic here, called at exit of with block
        return True

然后入口会传递一个 contextmanager 类的实例,并且可以引用在__init__方法中创建的任何内容(文件、套接字等)。exit 方法还接收在内部块和堆栈跟踪对象中引发的任何异常,或者None如果逻辑在没有引发的情况下完成。

然后我们可以像这样使用它:

with ContextManager(myarg):
    # ... code here ...

这对于管理资源生命周期、释放文件描述符、管理异常以及更复杂的用途(如构建嵌入式 DSL)等许多事情都很有用。

另一种(但等效的)构造方法是contextlib使用生成器来分离入口和出口逻辑的装饰器。

from contextlib import contextmanager

@contextmanager
def ContextManager(args):
    # Entrance logic here
    yield
    # Exit logic here
于 2013-09-13T04:27:41.453 回答
1

可以将with其视为在代码块上创建“主管”(上下文管理器)。监督者甚至可以被命名并在块内引用。当代码块正常或通过异常结束时,主管会收到通知,它可以根据发生的情况采取适当的行动。

于 2013-09-13T04:03:08.373 回答