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! Given its somewhat obscure status, I thought it would be worth asking:
with
statement designed to be used for? try..finally
than with
?In Python, the with statement replaces a try-catch block with a concise shorthand. More importantly, it ensures closing resources right after processing them. A common example of using the with statement is reading or writing to a file. A function or class that supports the with statement is known as a context manager.
The advantage of using a with statement is that it is guaranteed to close the file no matter how the nested block exits. If an exception occurs before the end of the block, it will close the file before the exception is caught by an outer exception handler.
Python is a high-level, interpreted, interactive and object-oriented scripting language. Python is designed to be highly readable. It uses English keywords frequently where as other languages use punctuation, and it has fewer syntactical constructions than other languages.
There are different types of statements in the Python programming language like Assignment statements, Conditional statements, Looping statements, etc. These all help the user to get the required output. For example, n = 50 is an assignment statement.
I would suggest two interesting lectures:
1. The with
statement is used to wrap the execution of a block with methods defined by a context manager. This allows common try...except...finally
usage patterns to be encapsulated for convenient reuse.
2. You could do something like:
with open("foo.txt") as foo_file: data = foo_file.read()
OR
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))
OR
lock = threading.Lock() with lock: # Critical section of code
3. I don't see any Antipattern here.
Quoting Dive into Python:
try..finally is good. with is better.
4. I guess it's related to programmers's habit to use try..catch..finally
statement from other languages.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With