--- author: '' category: '' date: 2012/01/07 23:06 description: '' link: '' priority: '' slug: BB963 tags: programming, python title: 'Python context managers: they are easy!' type: text updated: 2012/01/07 23:06 url_type: '' --- This comes from `this thread `_ in the Python Argentina mailing list (which I strongly recommend if you read spanish). I was the other day trying to do shell-script-like-things on python (as part of a monster setup.py) and I was annoyed that in shell it's easy to do this: .. code-block:: shell cd foo bar -baz cd - Or this: .. code-block:: shell pushd foo bar -baz popd Or this: .. code-block:: shell (cd foo && bar -baz) And on Python I had to do this, which is verbose and ugly: .. code-block:: python cwd = os.getcwd() try: os.chdir('foo') os.system('bar -baz') finally: os.chdir(cwd) This is what I wanted to have: .. code-block:: python with os.chdir('foo'): os.system('bar -baz') And of course, you can't do that. So, I asked, how do you implement that context manager? I got several answers. 1. That's available in Fabric: .. code-block:: python with cd("foo"): run("bar") 2. It's not hard to do: .. code-block:: python class DirContextM(object): def __init__(self, new_dir): self.new_dir = new_dir self.old_dir = None def __enter__(self): self.old_dir = os.getcwd() os.chdir(self.new_dir) def __exit__(self, *_): os.chdir(self.old_dir) 3. It's even easier to do: .. code-block:: python from contextlib import contextmanager @contextmanager def cd(path): old_dir = os.getcwd() os.chdir(path) yield os.chdir(old_dir) 4. That's cool, so let's add it to `path.py `_ 5. Maybe check for exceptions .. code-block:: python @contextmanager def cd(path): old_dir = os.getcwd() os.chdir(path) try: yield finally: os.chdir(old_dir) All in all, I learned how to do context managers, about contextlib, about fabric and about path.py. Which is not bad for 15 minutes :-)