什么是python;加上;为什么而设计的声明?

什么是python;加上;为什么而设计的声明?,python,language-features,with-statement,Python,Language Features,With Statement,今天我第一次看到Python的和语句。我已经轻松地使用Python好几个月了,甚至不知道它的存在!鉴于它的地位有点模糊,我认为值得一问: Python的with语句是什么 设计用来做什么 你怎么办 你用它做什么 有吗 我需要注意的问题,或者 与之相关的常见反模式 它的用途?在任何情况下,最好使用try..finally而不是with 为什么它没有得到更广泛的应用 哪些标准库类与之兼容 with语句适用于所谓的上下文管理器: 其思想是通过在离开“with”块后进行必要的清理来简化异常处理。一些p

今天我第一次看到Python的
语句。我已经轻松地使用Python好几个月了,甚至不知道它的存在!鉴于它的地位有点模糊,我认为值得一问:

  • Python的
    with
    语句是什么 设计用来做什么
  • 你怎么办 你用它做什么
  • 有吗 我需要注意的问题,或者 与之相关的常见反模式 它的用途?在任何情况下,最好使用
    try..finally
    而不是
    with
  • 为什么它没有得到更广泛的应用
  • 哪些标准库类与之兼容

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

    其思想是通过在离开“with”块后进行必要的清理来简化异常处理。一些python内置程序已经可以作为上下文管理器使用。

    请参见,最后有一个示例部分

    。。。Python的新语句“with” 语言 可以排除try/finally语句的标准用法


    我建议两个有趣的讲座:

    • “with”语句
    • 理解Python的 “with”语句
    1.
    with
    语句用于使用上下文管理器定义的方法包装块的执行。这允许封装常见的
    try…除了…finally
    使用模式以方便重用

    2. 你可以这样做:

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

    或(Python 3.1)

    3. 我在这里没有看到任何反模式。
    引述:

    试试……终于好了。使用更好。

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

    第1、2和3点得到了合理的阐述:

    4:它相对较新,仅在python2.6+中可用(或python2.5中使用
    从uuuu future\uuuuu导入带u语句

  • 我相信在我之前的其他用户已经回答了这个问题,所以我只是为了完整起见才添加它:
    with
    语句通过将常见的准备和清理任务封装在所谓的。有关更多详细信息,请参阅。例如,
    open
    语句本身就是一个上下文管理器,它允许您打开一个文件,只要在使用它的
    with
    语句的上下文中执行,就将其保持打开状态,并在离开上下文时将其关闭,无论您是因为异常还是在常规控制流期间离开它。因此,
    with
    语句的使用方式与C++中的类似:一些资源由
    with
    语句获取,并在您离开
    with
    上下文时释放

  • 一些示例包括:使用打开(文件名)为fp:
  • 打开文件,使用带锁的
    获取锁:
    (其中
    lock
    threading.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.stdin
    sys.stdout
    sys.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 <代码>带有语句是C++常用的成语的内置语言支持。它旨在允许安全获取和释放操作系统资源

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

    Python库中的许多资源遵循
    with
    语句所需的协议,因此可以直接使用。但是,任何人都可以通过实施记录良好的协议来获得可在with语句中使用的资源:


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

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

    比如说

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


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

    为了完整起见,我将添加最有用的
    用例和
    语句

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

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

    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
    

    我在超几何测试中经常用到这一点,超几何测试需要对由阶乘产生的大数进行除法。当你进行基因组规模计算时,你必须小心舍入和溢出错误。

    另一个开箱即用支持的例子,当你习惯了内置
    open()
    的行为方式时,一开始可能有点困惑的例子是流行数据库模块的
    connection
    对象,例如:

    • 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
      
      for row in lines:
          with open("outfile","a") as f:
              f.write(row)
      
      with open("outfile","a") as f:
          for row in lines:
              f.write(row)
      
      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
      
      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()
      
      with open(“file name”, “mode”) as file-var:
          processing statements
      
      function1(<complex and deep expression>)
      function2(<same complex and deep expression>)
      
      expr = <complex and deep expression>
      function1(expr)
      function1(expr)
      expr = None   # to delete all resources, or wait till end of function
      
      with <complex and deep expression> as expr:
        function1(expr)
        function1(expr)
      
      # expr is out of scope, hence any resources are deleted