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