Context manager

From Helpful
Jump to navigation Jump to search


Context managers bolt hook in some implied extra code, onto a code blocks, via syntactic sugar.

This is often used for some predicable, always-necessary cleanup, like doing resource management more automatically.



Python

This article/section is a stub — some half-sorted notes, not necessarily checked, not necessarily correct. Feel free to ignore, or tell me about it.


For example:

with open(filename) as file:
   file_data = file.read()

is roughly equivalent to

try:
   file = open(filename)
   file_data = file.read()
finally:
   file.close()

...because the built-in open() already implements the interface we're about to describe (and e.g. does a close in its __exit__).


At its core, the with statement takes an object; that object's its

  • __enter__() will be called at the start of the block
and returns the thing that will be assigned
  • __exit__() will be called afterwards
also if an exception is raised (so is much like a try-finally)



If it didn't do that, we might add it like in the following example (as it is, the example is redundant and pointless. A better example would be a database connection, but it'd take a few more lines to actually be runnable code)

You can write this more manually like:

class Test(object):
    def __init__(self, filename):  # __init__ isn't part of concept, but is how you get parameters in 
        self.filename = filename   #  (without which you'll find it hard to get __enter__ to return something useful to you)

    def __enter__(self):
        print('__enter__')
        self.fob = open(self.filename)
        return self.fob

    def __exit__(self, exc_type,exc_value, exc_traceback):
        print('__exit__')
        self.fob.close()

with Test('textfile') as t:
    print( t )


You may prefer to use the @contextlib.contextmanager decorator, which is mild trickery where you write a generator, everything before the yield is effectively run as part of __enter__, and that exactly-one yield is what gets assigned

@contextlib.contextmanager
def test(filename): # 
    f = open(filename)
    try:
        yield f
    finally:
        f.close()

with test('textfile') as t:
    print( t )


Notes:

  • there is also a way to ease creating a mixin

Javascript

This article/section is a stub — some half-sorted notes, not necessarily checked, not necessarily correct. Feel free to ignore, or tell me about it.

Nothing built in, but because ES6 has generators(good support since ~2017) you can insert both some before and after code, much like that second python example.

To copy-paste from [1]:

function* usingGroup() {
   console.group()
   try {
     yield;
   } finally {
     console.groupEnd();
   }
}

for(const _ of usingGroup()) {
   console.log('inside a group')
}

The same page also mentions a library to make this a little easier, imitating python.

C#

This article/section is a stub — some half-sorted notes, not necessarily checked, not necessarily correct. Feel free to ignore, or tell me about it.