“Python中的“with”语句被设计用于什么?”

2024-09-27 19:24:35 发布

您现在位置:Python中文网/ 问答频道 /正文

今天我第一次看到Pythonwith语句。我已经轻率地使用Python几个月了,甚至不知道它的存在!考虑到它的地位有些模糊,我想应该问问:

  1. 什么是Pythonwith语句 设计用于?
  2. 怎么办 你用它做什么?
  3. 有吗 我需要知道,或者 常见的反模式与 它的用途?在任何情况下,使用try..finally比使用with更好?
  4. 为什么不更广泛地使用呢?
  5. 哪些标准库类与之兼容?

Tags: 标准with模式情况语句用途try地位
3条回答
  1. 我相信在我之前,其他用户已经回答过这个问题,所以我添加它只是为了完整性:语句with通过将常见的准备和清理任务封装在所谓的context managers中,简化了异常处理。更多详细信息请参见PEP 343。例如,open语句本身就是一个上下文管理器,它允许您打开一个文件,只要执行是在使用它的with语句的上下文中,就保持它的打开状态,并在离开上下文时立即将其关闭,无论您是因为异常还是在常规控制流期间离开了它。因此,{{CD1}}语句可以以类似于C++中的{{a3}的方式使用:一些资源是由^ {< CD1> }语句获取的,并且在离开^ {< CD1> }上下文时释放。

  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
    

我建议两个有趣的讲座:

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()

或(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. 我在这里没有看到任何反模式。
引用Dive into Python

try..finally is good. with is better.

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

Python ^ {CD1>}语句是C++中常用的^ {A1}成语的内置语言支持。它旨在允许安全地获取和释放操作系统资源。

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

Python库中的许多资源都遵循with语句所需的协议,因此可以直接与它一起使用。但是,任何人都可以通过实现文档齐全的协议来生成可以在with语句中使用的资源:PEP 0343

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

相关问题 更多 >

    热门问题