Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

Python Object-Oriented Python Advanced Objects Emulating Built-ins

Why do we need to make our own built in dunder function __len__ when the len() function works just fine?

It's hard to keep up when all the code is being done in the repl I cant even see what the initial code was since the repl takes up so much space. I am confused becuase i dont understand why we cant just use the normal len function to find out the length of our inventory. Why do we need to go and create the method len?

3 Answers

Consider what would happen if we had a more complex Inventory class, with multiple list attributes to hold different types of items:

class Inventory:
    def __init__(self):
        self.weapons = []
        self.armor = []

If we did not override __len__ we would need to manually get the length of each of these attributes whenever we needed to check the number of items a character is holding:

#get the number of items in the character's inventory
inventory_size = len(self.inventory.weapons) + len(self.inventory.armor)

If we were to add another list attribute to the Inventory class, we would need to go find every place in our code that performs this calculation and update the attributes we are checking the length for:

class Inventory:
    def __init__(self):
        self.weapons = []
        self.armor = []
        self.money = []

Elsewhere in our code:

#get the number of items in the character's inventory
inventory_size = len(self.inventory.weapons) + len(self.inventory.armor) +  len(self.inventory.money)

But, if we put this logic into the __len__ function for Inventory:

class Inventory:
    def __init__(self):
        self.weapons = []
        self.armor = []
        self.money = []

    def __len__(self):
        return len(self.weapons) + len(self.armor) + len(self.money)

We can now just call len() on the instance of the Inventory class itself:

#get the number of items in the character's inventory
inventory_size = len(self.inventory)

This also lets us have more control over how other classes interact with the Inventory class. For example, if we did not want money to be counted towards the total size of the character's inventory, we can exclude the length of that list from the value returned by the len() function:

class Inventory:
    def __init__(self):
        self.weapons = []
        self.armor = []
        self.money = []

    def __len__(self):
        return len(self.weapons) + len(self.armor)
Jeff Muday
MOD
Jeff Muday
Treehouse Moderator 27,918 Points

Your observation is correct.

Kenneth is preparing you to think through some advanced scenarios. For example, if you are building a class from a parent object that doesn't have a __len__ method you would have to write your own if you want to use len() on your instantiated objects.

Also, think about overwriting the behavior of len in a case were is needed, for any wild reason you could end up needing to return a fixed number, or the len of another attribute.

Jeff Muday
MOD
Jeff Muday
Treehouse Moderator 27,918 Points

Nate Paradis @nateparadis comment provides a great example of the value of being able to override the the dunder len __len()__ which can provide additional context on iteration.

One of the other methods one might want to override is to dunder iter __iter()__ and the dunder next __next()__ to allow the game (or game-mod) to look at inventory item labels that are different types (e.g. Weapons and Armor) that are carried.

https://www.programiz.com/python-programming/iterator