什么是蟒蛇"为什么设计的语句?

我今天第一次遇到Python with语句。我已经简单地使用Python几个月了,甚至不知道它的存在!鉴于它的地位有些模糊,我认为有必要问一下:

    Python with语句是什么 设计用于?李< / > <李>什么 你用它干什么?李< / >
  1. 有任何 我需要注意的问题,还是 相关联的常见反模式 它的使用?在任何情况下,使用try..finally比使用with更好?李< / >
  2. 为什么它没有被更广泛地使用呢?
  3. 哪些标准库类与它兼容?
118924 次浏览

with语句适用于所谓的上下文管理器:

http://docs.python.org/release/2.5.2/lib/typecontextmanager.html

这个想法是通过在离开with块后进行必要的清理来简化异常处理。一些python内置程序已经作为上下文管理器工作。

参见PEP 343 - 'with'语句,末尾有一个示例部分。

< p >…新的语句"with"到Python 制造语言 try/finally语句的标准用法可以被排除

我想推荐两堂有趣的课:

<强> 1。 with语句用于用上下文管理器定义的方法包装块的执行。这允许封装常见的try...except...finally使用模式,以便方便重用

<强> 2。 你可以这样做:

with open("foo.txt") as foo_file:
data = foo_file.read()

from contextlib import nested
with nested(A(), B(), C()) as (X, Y, Z):
do_something()

OR (Python 3.1)

with open('data') as input_file, open('result', 'w') as output_file:
for line in input_file:
output_file.write(parse(line))

lock = threading.Lock()
with lock:
# Critical section of code

<强> 3。 我在这里没有看到任何反模式。
引用深入了解Python: < / p >

试一试,终于好了。有更好。

< >强4。 我猜这与程序员习惯使用其他语言中的try..catch..finally语句有关

第1点、第2点和第3点得到了很好的阐述:

4:相对较新,仅在python2.6+(或使用from __future__ import with_statement的python2.5中可用)

  1. 我相信在我之前已经有其他用户回答过这个问题,所以我只是为了完整性而添加它:with语句通过将常见的准备和清理任务封装在所谓的上下文管理器中简化了异常处理。更多细节可以在PEP 343中找到。例如,open语句本身就是一个上下文管理器,它允许你打开一个文件,只要在你使用它的with语句的上下文中执行,它就保持打开状态,并在你离开上下文时立即关闭它,无论你是因为异常还是在常规控制流中离开它。因此,with语句可以以类似于c++中的RAII模式的方式使用:一些资源由with语句获取,并在离开with上下文时释放。

  2. 一些例子是:使用with open(filename) as fp:打开文件,使用with lock:获取锁(其中lockthreading.Lock的一个实例)。你也可以使用contextlib中的contextmanager装饰器来构造你自己的上下文管理器。例如,当我必须临时更改当前目录,然后返回到我所在的位置时,我经常使用这个:

    from contextlib import contextmanager
    import os
    
    
    @contextmanager
    def working_directory(path):
    current_dir = os.getcwd()
    os.chdir(path)
    try:
    yield
    finally:
    os.chdir(current_dir)
    
    
    with working_directory("data/stuff"):
    # do something within data/stuff
    # here I am back again in the original working directory
    

    下面是另一个例子,它临时将sys.stdinsys.stdoutsys.stderr重定向到其他一些文件句柄,并稍后恢复它们:

    from contextlib import contextmanager
    import sys
    
    
    @contextmanager
    def redirected(**kwds):
    stream_names = ["stdin", "stdout", "stderr"]
    old_streams = {}
    try:
    for sname in stream_names:
    stream = kwds.get(sname, None)
    if stream is not None and stream != getattr(sys, sname):
    old_streams[sname] = getattr(sys, sname)
    setattr(sys, sname, stream)
    yield
    finally:
    for sname, stream in old_streams.iteritems():
    setattr(sys, sname, stream)
    
    
    with redirected(stdout=open("/tmp/log.txt", "w")):
    # these print statements will go to /tmp/log.txt
    print "Test entry 1"
    print "Test entry 2"
    # back to the normal stdout
    print "Back to normal stdout again"
    

    最后,另一个例子创建了一个临时文件夹,并在离开上下文时清理它:

    from tempfile import mkdtemp
    from shutil import rmtree
    
    
    @contextmanager
    def temporary_dir(*args, **kwds):
    name = mkdtemp(*args, **kwds)
    try:
    yield name
    finally:
    shutil.rmtree(name)
    
    
    with temporary_dir() as dirname:
    # do whatever you want
    

Python with语句是c++中常用的Resource Acquisition Is Initialization习语的内置语言支持。它的目的是允许安全获取和释放操作系统资源。

with语句在作用域/块中创建资源。您可以使用块中的资源编写代码。当块退出时,无论块中代码的结果如何(即块是正常退出还是因为异常退出),资源都将被干净地释放。

Python库中的许多资源遵循with语句所要求的协议,因此可以与它一起开箱即用。然而,任何人都可以通过实现良好记录的协议PEP 0343来创建可以在with语句中使用的资源

当您在应用程序中获取必须显式放弃的资源(如文件、网络连接、锁等)时,请使用它。

反模式的一个例子可能是在循环内部使用with,而在循环外部使用with会更有效

例如

for row in lines:
with open("outfile","a") as f:
f.write(row)

vs

with open("outfile","a") as f:
for row in lines:
f.write(row)

第一种方法是为每个row打开和关闭文件,这可能会导致性能问题,而第二种方法只打开和关闭一次文件。

同样为了完整起见,我将为with语句添加最有用的用例。

我做了很多科学计算,对于一些活动,我需要Decimal库进行任意精度计算。我的代码的某些部分我需要较高的精度,而对于大多数其他部分我需要较低的精度。

我将默认精度设置为一个较低的数字,然后使用with来获得某些部分的更精确的答案:

from decimal import localcontext


with localcontext() as ctx:
ctx.prec = 42   # Perform a high precision calculation
s = calculate_something()
s = +s  # Round the final result back to the default precision

我在Hypergeometric Test中经常使用这种方法,因为它需要对大数进行阶乘。当你进行基因组规模计算时,你必须小心四舍五入和溢出错误。

另一个开箱即用支持的例子是流行数据库模块的connection对象,例如:

connection对象是上下文管理器,因此可以在with-statement中开箱即用,但在使用上述对象时请注意:

with-block结束时,有异常或没有异常,连接未关闭. 连接未关闭。如果with-block以异常结束,则事务将回滚,否则事务将被提交。

这意味着程序员必须小心自己关闭连接,但允许获取一个连接,并在多个with-statements中使用它,如psycopg2文档所示:

conn = psycopg2.connect(DSN)


with conn:
with conn.cursor() as curs:
curs.execute(SQL1)


with conn:
with conn.cursor() as curs:
curs.execute(SQL2)


conn.close()

在上面的例子中,你会注意到psycopg2cursor对象也是上下文管理器。从行为的相关文档中:

cursor退出with-block时,它将被关闭,释放最终与它相关的所有资源。事务的状态不会受到影响。

在python中,通常使用" "语句打开文件,处理文件中的数据,并在不调用close()方法的情况下关闭文件。" with "语句通过提供清理活动简化了异常处理。

with的一般形式:

with open(“file name”, “mode”) as file_var:
processing statements

注意:不需要在file_var.close()上调用close()来关闭文件

这里的答案很棒,但我只想补充一个帮助我的简单答案:

with open("foo.txt") as file:
data = file.read()
  • open返回一个file
  • 自2.6以来,python将方法__enter____exit__添加到file
  • with类似于调用__enter__的for循环,运行一次循环,然后调用__exit__
  • with适用于任何具有__enter____exit__的实例

一个文件被锁定,在关闭之前不能被其他进程重用,__exit__关闭它。

来源:http://web.archive.org/web/20180310054708/http://effbot.org/zone/python-with-statement.htm