A Gentle Introduction to Context Managers
Aly Sivji
@CaiusSivjus
About Me
We’ve all seen this before....
Source: Python 3 Tutorial
with Statement
Source: Python Docs
Context Manager
Note on __magic__ methods
Trace execution of with statement
class Foo:� def __enter__(self):� print('__enter__ called')� return self�� def __exit__(self, exc_type, exc_value, exc_tb):� print('__exit__ called')
>>> with Foo() as obj:�... print('inside with')
...
__enter__ called
inside with
__exit__ called
Code
REPL
Exceptions
Exception inside with statement
class Foo:� def __enter__(self):� print('__enter__ called')� return self�� def __exit__(self, exc_type, exc_value, exc_tb):� print('__exit__ called')
>>> with Foo() as obj:�... print('inside with')
... raise Exception('error')
...
__enter__ called
inside with
__exit__ called
----------------------------------�Exception Traceback (most recent call last)
Code
REPL
Handling exception inside with statement
class Foo2:� def __init__(self):� print('__init__ called')
def __enter__(self):� print('__enter__ called')� return self
def __exit__(self, exc_type, exc_value, exc_tb):� print('__exit__ called')� if exc_type:� # code to handle� print('exception handled')� return True
Code 1
Code 2
Handling exception inside with statement (2)
>>> with Foo2() as obj:�... print('inside with')
... raise Exception('error')
...
__init__ called
__enter__ called
inside with
__exit__ called
exception handled
REPL
Output
When to use Context Managers: Open/Close Files
with open('my_file.txt') as f:� data = f.readlines()
When to use Context Managers: Testing
import pytest��def test_zero_division():� with pytest.raises(ZeroDivisionError):� 1 / 0
Source: pytest Docs
When to use Context Managers: Other Use Cases
contextlib Package
Source: Python Docs
Creating a Context Manager: Project Background
Source: Project Code
Using try...finally block
def download_tweets_by_hashtag_nonpythonic(hashtag):� tweets = []� try:� client = MongoClient(mlab_uri)� db = client.get_default_database()� coll = db[collection]� tweets = coll.find({"entities.hashtags.text":f"{hashtag}"})� finally:� client.close()� return tweets
Source: Project Code
Creating a Context Manager Object
class MongoCollection(object):� def __init__(self, uri, collection):� self.client = MongoClient(uri)� self.db = self.client.get_default_database()� self.collection = self.db[collection]�� def __enter__(self):� return self.collection�� def __exit__(self, exc_type, exc_value, exc_tb):� self.client.close()
Source: Project Code
Using Context Manager in with Statement
def download_tweets_by_hashtag(hashtag):�� with MongoCollection(mlab_uri, collection) as coll:� tweets = coll.find({'entities.hashtags.text':f'{hashtag}'})�� return list(tweets)
Source: Project Code
Additional Resources
Thank You
Github: alysivji
Twitter: @CaiusSivjus
Blog: https://alysivji.github.io
Slides: http://bit.ly/context-manager-chipy