Python’s “with as” Statement in Julia, JavaScript, Lua and Other Languages

One of the challenges for me to grasp the with as feature in Python, its need is not apparent unless you have a deeper understanding of the limits of the Python language.

A Ruby, Julia, Lua, Go, JavaScript or Swift developer for instance would not need this statement added. Why is that?

At the heart of the problem is a cherished feature by many Python developers: the use of indentation to indicate code blocks.

In JavaScript I could write e.g.

openfile('foobar.txt', function(file) {
// called after file has been opened
// file is a handle to the open file
read_data(file)
...
});

Lua would support a similar pattern:

openfile("foobar.txt", function(file)
-- called after file has been opened
-- file is a handle to the open file
read_data(file)
...
end)

Now imagine what that would look like in Python:

openfile("foobar.txt", def (file):
# called after file has been opened
# file is a handle to the open file
read_data(file)
...

This would not work. It would not be possible for the compiler to figure out how things are nested. Should double indentation mean things are more deeply nested e.g.?

It illustrates the benefit of having a symbol to signal the end of a block of code rather than a change in indentation.

Using Higher Order Functions With Closures For Resources Allocation and Cleanup

function openfile(callback, filename::String)
file = open(filename)
callback(file)
close(file)
end

We can use this function in different ways. For instance this will read a line and print it to screen, using the syntax for one-line closures/lambda.

openfile(file -> print(readline(file)), "foobar.txt")

It may look a bit backwards to put the lambda expression as the first argument. But in Julia there are good reasons to do that. That is because the do-end statement placed at the end of a function call, translates into a closure/lambda as first argument to called function. So the line above is equivalent to writing:

openfile("foobar.txt") do file
print(readline(file))
end

This is very handy syntax because it makes it easy to write inline closures with multiple lines of code.

The beauty of this way of opening and closing files, is that you will not forget to close the file.

The Python Solution

class openfile:
def __init_(self, filename):
self.filename
def __enter__(self):
self.file = open(self.filename)
return file
def __exit__(self, exc_type, exc_val, exc_tb):
close(self.file)

Don’t run this code, as it is really just meant to explain the concept of a context manager class.

We can use this class to open and read from a file in this manner:

with openfile("foobar.txt") as file:
print(readline(file))

So let me explain how this works:

  1. First the constructor of the openfile class get called, and we store the name of the file we want to open.
  2. An instance of the openfile class is passed to the with-as construct, which causes its __enter__ method to get called. It is supposed to acquire our desired resources. A file handle in this case.
  3. The returned object becomes the argument to as. So as file refers to the object returned from __enter__. The names don't have to match. We could have written as foobar instead.
  4. When all the code inside the with-as block has been run, Python will invoke __exit__ to release resources. This will also get called in case there are any exceptions thrown.

Please keep in mind I’ve just skimmed the surface. I did not elaborate on how exceptions are treated and what all the arguments to __exit__ are. This article was not meant to explain the ins and outs of with-as but rather why it exists.

There are lots of variations in in how can make these context manager classes, either by subclassing or using decorators.

Written by

Geek dad, living in Oslo, Norway with passion for UX, Julia programming, science, teaching, reading and writing.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store