What is the python “with” statement designed for?

后端 未结 10 1836
心在旅途
心在旅途 2020-11-21 07:52

I came across the Python with statement for the first time today. I\'ve been using Python lightly for several months and didn\'t even know of its existence! G

相关标签:
10条回答
  • 2020-11-21 08:06

    In python generally “with” statement is used to open a file, process the data present in the file, and also to close the file without calling a close() method. “with” statement makes the exception handling simpler by providing cleanup activities.

    General form of with:

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

    note: no need to close the file by calling close() upon file-var.close()

    0 讨论(0)
  • 2020-11-21 08:07
    1. I believe this has already been answered by other users before me, so I only add it for the sake of completeness: the with statement simplifies exception handling by encapsulating common preparation and cleanup tasks in so-called context managers. More details can be found in PEP 343. For instance, the open statement is a context manager in itself, which lets you open a file, keep it open as long as the execution is in the context of the with statement where you used it, and close it as soon as you leave the context, no matter whether you have left it because of an exception or during regular control flow. The with statement can thus be used in ways similar to the RAII pattern in C++: some resource is acquired by the with statement and released when you leave the with context.

    2. Some examples are: opening files using with open(filename) as fp:, acquiring locks using with lock: (where lock is an instance of threading.Lock). You can also construct your own context managers using the contextmanager decorator from contextlib. For instance, I often use this when I have to change the current directory temporarily and then return to where I was:

      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
      

      Here's another example that temporarily redirects sys.stdin, sys.stdout and sys.stderr to some other file handle and restores them later:

      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"
      

      And finally, another example that creates a temporary folder and cleans it up when leaving the context:

      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
      
    0 讨论(0)
  • 2020-11-21 08:07

    Again for completeness I'll add my most useful use-case for with statements.

    I do a lot of scientific computing and for some activities I need the Decimal library for arbitrary precision calculations. Some part of my code I need high precision and for most other parts I need less precision.

    I set my default precision to a low number and then use with to get a more precise answer for some sections:

    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
    

    I use this a lot with the Hypergeometric Test which requires the division of large numbers resulting form factorials. When you do genomic scale calculations you have to be careful of round-off and overflow errors.

    0 讨论(0)
  • 2020-11-21 08:12

    An example of an antipattern might be to use the with inside a loop when it would be more efficient to have the with outside the loop

    for example

    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)
    

    The first way is opening and closing the file for each row which may cause performance problems compared to the second way with opens and closes the file just once.

    0 讨论(0)
提交回复
热议问题