In my path to mastering python I decided what better way to do so that to teach. To make it even more interesting I am taking this from the perspective of how does that feature in C# work in python, given i would do this in C# this way, how can I do it in Python? This is the first post of a series, looking at using directives in C#, context managers in Python.
Using Directives in Python (Context Managers)
Context Managers allow you to allocate and release resources precisely when you want to. They in particular help in guaranteeing release of resources even if an error occurs.
Imagine this scenario:
file = open('source.tct', 'w') file.write('Some text') file.close()
If an error occurs while writing to the file the code to close the file resource would not be called. One way to addres this is as follows:
file = open('source.tct', 'w') try: file.write('Some text') finally: file.close()
The context managers provide syntactic sugar to do just this as follows:
with open('source.txt', 'w') as opened_file: opened_file.write('Some text')
Behind the scenses something interesting is happening, let's have a look at how to implement context managers that will make this clear. This can be done in two ways.
Implementing Context Managers as classes
At the very least a context manager has an
__exit method defined which are executed and beginning and end of scope (context). If an exception occurs, Python passes the type, value and traceback of the exception to the
__exit method. If
__exit** returns True then the exception was gracefully handled.
Let's consider a scoped context manager that executes a one lambda on start of the scope and another on end of the scope (context).
from typing import Callable class ScopedActions(object): startup: Callable[, None] cleanup: Callable[, None] name: str def __init__(self, name: str, startup: Callable[, None], cleanup: Callable[, None]): self.name = name self.startup = startup self.cleanup = cleanup def __enter__(self): self.startup() return self def __exit__(self, type, value, traceback): self.cleanup() with ScopedActions(name='test', startup=lambda: print('started'), cleanup=lambda: print('finished')) as scoped: print('Executing:', scoped.name)
Implementing Context Managers as generators
Context managers can also be implementing in a more succint way using generators as functions two parts, the context start and context end separater by the yield keyword. Exceptions in this scenario can be handled by a traditional try statement which is also more intuitive. This makes use of the
from contextlib import contextmanager from typing import Callable @contextmanager def scoped_actions(name: str, startup: Callable[, None], cleanup: Callable[, None]): startup() yield name cleanup() with scoped_actions(name='test', startup=lambda: print('started'), cleanup=lambda: print('finished')) as name: print('Executing:', name)
Checkout the complete code sample used in this gist on github.
Subscribe to Thulani S. Chivandikwa
Get the latest posts delivered right to your inbox