I am new to this, and am just trying to understand the with
statement. I understand that it is supposed to replace the try
/except
block.
Now suppose I do something like this:
try:
name='rubicon'/2 # to raise an exception
except Exception as e:
print "no not possible"
finally:
print "Ok I caught you"
How do I replace this with a context manager?
The contextlib.contextmanager function decorator provides a handy way of providing a context manager without the need to write a full-fledged
ContextManager
class of your own (with__enter__
and__exit__
methods, so you don't have to remember the arguments to the__exit__
method, or that the__exit__
method mustreturn True
in order to suppress the exception). Instead, you write a function with a singleyield
at the point you want thewith
block to run, and you trap any exceptions (that effectively come from theyield
) as you normally would.Why go to the extra trouble of writing a context manager? Code re-use. You can use the same context manager in multiple places, without having to duplicate the exception handling. If the exception handling is unique to that situation, then don't bother with a context manager. But if the same pattern crops up again and again (or if it might for your users, e.g., closing a file, unlocking a mutex), it's worth the extra trouble. It's also a neat pattern to use if the exception handling is a bit complicated, as it separates the exception handling from the main line of code flow.
with
statements or context managers are there to aid with resources (although may be used for much more).Let's say you opened a file for writing:
You now have an open file handle. During the handling of your file, no other program can write to it. In order to let other programs write to it, you must close the file handle:
But, before closing your file an error occured:
What will happen now is that the function or entire program will exit, while leaving your file with an open handle. (CPython cleans handles on termination and handles are freed together with a program but you shouldn't count on that)
A with statement ensures that as soon as you leave it's indentation, it will close the file handle:
with
statements may be used for many more things. For example:threading.Lock()
Almost everything done with a context manager can be done with
try: ... finally: ...
but context managers are nicer to use, more comfortable, more readable and by implementing__enter__
and__exit__
provide an easy to use interface.Creating context managers is done by implementing
__enter__()
and__exit__()
in a normal class.__enter__()
tells what to do when a context manager starts and__exit__()
when a context manager exists (giving the exception to the__exit__()
method if an exception occurred)A shortcut for creating context managers can be found in contextlib. It wraps a generator as a context manager.
with
doesn't really replacetry
/except
, but, rather,try
/finally
. Still, you can make a context manager do something different in exception cases from non-exception ones:The
return True
part is where the context manager decides to suppress the exception (as you do by not re-raising it in yourexcept
clause).The
with
in Python is intended for wrapping a set of statements where you should set up and destroy or close resources. It is in a way similar totry...finally
in that regard as the finally clause will be executed even after an exception.A context manager is an object that implements two methods:
__enter__
and__exit__
. Those are called immediately before and after (respectively) thewith
block.For instance, take a look at the classic
open()
example:Open returns a
File
object that implements__enter__
more or less likereturn self
and__exit__
likeself.close()
.The components of context manager
1.you should implement a __enter__ method that return a object 2.implement a__exit__ method
example
I will give a simple example to show you why we need context manager.During the winter of xinjiang, china , you should close a door immediately when you open a door.if you forget to close it ,you will get ***.
class Door: def __init__(self): self.doorstatus='the door was closed when you are not in home' print(self.doorstatus) def __enter__(self): print('i have opened the door') return self def __exit__(self,*args): print('pong!the door has closed') def fetchsomethings(self): print('i have fetched somethings')
when fetch a things at home,you should open a door,fetch somethings and close the door.with Door() as dr: dr.fetchsomethings()
the output is:the door was closed when you are not in home i have opened the door i have fetched somethings pong!the door has closed
Explation
when you initiate a Door class ,it will call__init__ method that will print "the door was closed when you are not in home" and __enter__ method that will print "i have opened the door" and return a door instance called dr. when call self.fetchsomethings in with block,the method will print "i have fetched somethings".when the block is finished.the context manager will invoke __exit__ method and it will print "pong!the door has closed" .when you donot use with keyword ,__enter__and __exit__ will not be invoked!!!!