In this article we will take a look at how you can implement a number of methods in your classes that will improve the readability of your code and make it easier to use code you have written. The methods in this post are usable when your code implements some sort of containers. In this use case you should see a container as an object containing other objects (and not some form of light weight virtualisation).

When you implement a container type in your codebase you make working with those types a lot more enjoyable and the code using those types will be a lot more readable.

Contents

Object string representation using __str__
Length of an object using __len__
Iterating over an object using __iter__
Getting an item using __getitem__
Setting an item using __setitem__
Deleting an item using __delitem__
Testing membership using __contains__

ShoppingCart example

In the examples that follow we will work with a hypothetical  ShoppingCart  class. Currently our class is a very simple example:

This is very straightforward, upon creating an instance of our ShoppingCart  class we pass it some items to store. In it’s most simple form, here is a way we would use our shoppingcart:

We create a list of strings to represent our items and pass this list to our class when we create the my_cart  object.

This works nicely but I don’t really like the output of the  print function. We get the default string representation of a Python object, and frankly it’s ugly and very human-unfriendly. Let’s change that!

Object string representation using __str__

Whenever we need to get a string representation of an object the Python interpreter will use the  __str__ method on our class. If we don’t provide such a method, Python defaults back to the builtin  __repr__ method, a seen above.

So let’s improve our Shoppingcart:

Here we have added a  __str__ method to our Shoppingcart class that returns a more human-friendly representation of our Shoppingcart. I went ahead and used the new f-strings from Python 3.6 but you are free to build your string representation as you see fit of course. The return value of __str__  must be a string object.

If we want to  print() our shoppingcart now, we get output that is much more usable to both the user and the developer:

You might be tempted to think, “I don’t print my objects or variables to the console” or leave out the  __str__() method because you’re developing web applications. But it makes sense to include this method in virtually all your classes. Whenever a developer (including you) might debug code that uses your classes, the __str__()  method will be there to help him understand:

Improve debugging by using __str__() methods in your classes

Resources: Python documentation for __str__

Length of an object using __len__

Getting the length of an object may seem strange, but in a lot of cases it makes sense. In our Shoppingcart example we might want to get the number of items in the cart:

and honestly, this isn’t bad code. We can however make it even easier for the developers using our Shoppingcart class by implementing a  __len__() method in our class:

Very simple and straightforward, we return value of the  __len__() method of our items member in the Shoppingcarts implementation. Note I have removed some implementation on line 6 in order to reduce the example size, each example builds upon the previous one.

By implementing the  __len__() method we can write code that is a bit cleaner, and hides some of the implementation complexity from the user of our class:

Resources: Python documentation for __len__

Iterating over an object using __iter__

In our Shoppingcart example, we will probably need to loop over all items in our cart. With the current version of our ShoppingCart class, we will have to do something like this:

Like in the previous section, we require the user of our class to know about the internals of our ShoppingCart class. We still aren’t that good when it comes to encapsulation. Let’s make our code a little better and nicer to read.

We have implemented a  __iter__() method in our class so we can iterate over our ShoppingCart. The implementation returns an iterator over our  items member, effectively allow us to write

Getting an item using __getitem__

A common use case for classes such as our ShoppingCart is retrieving a particular item. If you are a migrant programmer coming from Java or C languages you might be tempted to write code such as

But that’s not very Pythonic. Why bother with writing accessor methods when you have the full power of  __getitem__() at your disposal? Using  __getitem__() you class gets awesome powers: it enables you to get data from your class using dictionary-like syntax:  my_cart['item'] . Here’s how.

 

Resources: Python documentation for __getitem__

Setting an item using __setitem__

Similar to getting data from your container class using  __getitem__()  you can give your class dictionary-like syntax to ‘set’ attributes:  my_cart['item'] = new_item . Implementation is, again, quite straightforward.

For the implementation of our  __setitem__()  method we chose to insert the key-value into the dictionary of our  items member.

Resources: Python documentation for __setitem__

Deleting an item using __delitem__

Similar to getting and setting items using dictionary notation you can implement the  __delitem__()  method to allow for item deletion using  del my_cart['item1'] . Our plain and simple implementation:

Resources: Python documentation for _delitem__

Testing membership using __contains__

The last method we will look at is the __contains__ method. As the name implies this method will allow us to check if an item is contained in our container object. The pythonic way of doing this is using the  item in container clause you should/might be familiar with.

Resources: Python documentation for _contains__

Conclusion

Using the methods above allows you to implement a container type in your code base. This will make your code a lot more easier to read and allows it to fit in seamlessly with a lot of the Pythonic ways of doing things.

2 Thoughts on “Improving your code with container methods”

  • You could also just subclass dict:

    class ShoppingCart(dict):
    def __str__(self):
    return f’Shoppingcart with items: {“, “.join(iter(self))}’

  • Subclassing dict is fine. Even more, you’ve presented a lot of complexity to “simplify” using a class for your shopping cart, most of which argues for it not needing to be a class in the first place. If you left your shopping cart as a dict, all of the stuff you’ve shown “just works”. Don’t write Java in Python just because you can.

Leave a Reply

Your email address will not be published. Required fields are marked *