Resource Acquisition is Initialization (RAII)

This post will be about the Resource Acquisition is Initialization (RAII) pattern which is a creational pattern. This is going to be the first non Gang of Four pattern I will write about.

The Purpose

The idea behind this pattern is to correctly dispose of all the resources that you acquire. This pattern was first written about by Bjarne Stroustrup, the creator of C++. The most common examples of this pattern are in opening and closing files and web sockets. It is also important in controlling mutexes so you can write tread safe code.

The Pattern

This pattern concerns a single class, and as such I will only describe it’s implementation I won’t give a UML diagram.

I know this is a post about python, but as this pattern originated in C++ I am going to start talking about it there.

In a C++ class, like most object oriented languages, you have a constructor and destructor. So in C++ you would implement RAII in the following way.

class RAII {
  // Constructor, acquire resources here

  // Destructor, release resources here

  // acquire resource i.e. open file

  // release resource i.e. close file

In C++ whenever a class instance goes out of scope the destructor will be called. This is a deterministic process managed by the compiler and that means that you are guaranteed to release the resources. Leading on from this you might imagine you can implement RAII in the following way in python.

class RAII(object):

        # acquire resource

        # release resource

This is however wrong! As python does not use deterministic garbage collection __del__ will not necessarily ever get called. Here there is more information about when/how/if __del__ is called. As a side not python is even not guaranteed to be garbage collected, this is an implementation detail for each specific interpreter, see here.

So how do we implement this pattern in python? We can use the context manager language feature. Context managers were introduced to python in version 2.5 and are called using the with statement. So the old code

text_file = open("file.txt", "r")
# do some reading

Should instead be written as.

with open("file.txt", "r") as text_file:
    # do some reading

That is the calling code, In the next section I will go over how you can create custom classes to do RAII.

Implementation of a Context Manager

Making a context manager needs two magic methods __enter__ and __exit__.

__enter__ is called from the with statement, it takes no argument and it should return the context manager. In most examples you will find that the class it’s is the context manager, but it doesn’t have to be.

__exit__ is called when the with block is exited, either naturally or through and exception. This function takes three arguments; the type of exception, e.g. TypeException, the instance of the exception, and a traceback object which can be read with the traceback module. If there was no exception raised, all three of these will have None value. If you want to ignore the exception (or one wasn’t raised) __exit__ should return True, otherwise it should return False.

So a context manager will look like this.

class ContextManager(object):

    def __enter__(self):
        return self

    def __exit__(self, exception_type, exception, traceback):
        # return if there was an exception
        return all(
          arg is None for arg in [exception_type, exception, traceback]

An Example Usage

My example usage for this is a Box. After you open a box you always need to close it.

The file for this example can be found here.

class Box(object):
    def __init__(self, name):
        self.name = name

    def __enter__(self):
        print("Box " + self.name + " Opened")
        return self

    def __exit__(self, exception_type, exception, traceback):
        all_none = all(
            arg is None for arg in [exception_type, exception, traceback]
        if (not all_none):
            print("Exception: \"%s\" raised." %(str(exception)))
        print("Box Closed")
        return all_none

This is then called with the following code.

if (__name__ == "__main__"):
    with Box("tupperware") as simple_box:
        print("Nothing in " + simple_box.name)
    with Box("Pandora's") as pandoras_box:
        raise Exception("All the evils in the world")

Which outputs.

Box tupperware Opened
Nothing in tupperware
Box Closed

Box Pandora's Opened
Exception: "All the evils in the world" raised.
Box Closed

Traceback (most recent call last):
  File "./Creational/ResourceAcquisitionIsInitialization.py", line 33, in <module>
    raise Exception("All the evils in the world")
Exception: All the evils in the world

Note that although the exception was raised and the program exited the box was still closed.

All of the code for the design patterns can be found here.

Thanks for reading.


0 Responses to “Resource Acquisition is Initialization (RAII)”

  1. Leave a Comment

What did you think?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Call Me
Endorse davidcorne on Coderwall



© 2013 by David Corne.

Creative Commons License

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.

%d bloggers like this: