我是 Python 新手。在一个连接mysql并获取数据的教程中,我看到了该with语句。我读过它,它与try-finally块有关。但我找不到一个我能理解的更简单的解释。
3 回答
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()
将作为单个事务提交或回滚命令序列。这意味着您不必太担心异常或其他不寻常的代码路径——无论您如何离开代码块,事务都会得到处理。
从根本上说,它是一个对象,它使用在入口和出口时调用的自定义逻辑划分代码块,并且可以在其构造中接受参数。您可以使用类定义自定义上下文管理器:
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
可以将with其视为在代码块上创建“主管”(上下文管理器)。监督者甚至可以被命名并在块内引用。当代码块正常或通过异常结束时,主管会收到通知,它可以根据发生的情况采取适当的行动。