本问题已经有最佳答案,请猛点这里访问。
我是Python的新手。在一个关于连接到MySQL和获取数据的教程中,我看到了with语句。我读到它,它与try-finally块有关。但我找不到一个我能理解的更简单的解释。
stackoverflow.com/questions/3012488/…
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看作是在代码块上创建一个"主管"(上下文管理器)。甚至可以给主管一个名称并在块中引用。当代码块正常结束或通过异常结束时,会通知主管,主管可以根据发生的情况采取适当的措施。