Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python Object-Oriented Python (retired) Inheritance __str__

Python "magic methods" clarification

I'm having trouble wrapping my head around what these methods ( x ) do exactly. I've found a few links that explain them somewhat, but I really haven't been able to pinpoint exactly what they are intended for. Can someone help me clarify exactly what they do? Are they specifically for objects/inheritance? Thanks in advance! I can post the links to the articles I've found if anyone is interested.

1 Answer

Dan Johnson
Dan Johnson
40,532 Points

The magic methods cover a lot of ground but one large aspect of them is operator overloading. I threw together an example Vector class to showcase some of them:

class Vector(object):
    def __init__(self, components=[]):
        self.components = components

    def __add__(self, other):
        # Defines the behaviour for addition.
        # Since we're making a Vector class we'll add corresponding components together
        if len(self) == len(other):
            result = []
            for left, right in zip(self, other):
                result.append(left + right)
            return result
        else:
            raise ArithmeticError()

    def __sub__(self, other):
        # Similar setup to addition, just subtracting each component.
        if len(self) == len(other):
            result = []
            for left, right in zip(self, other):
                result.append(left - right)
            return result
        else:
            raise ArithmeticError()

    def __mul__(self, other):
        # We'll do something more suited to a vector and return the dot product
        if len(self) == len(other):
            result = 0
            for left, right in zip(self, other):
                result += left * right
            return result
        else:
            raise ArithmeticError()

    def __eq__(self, other):
        # We'll treat the vectors as equal if their components are equivalent and in the same order
        # This is the default behaviour for a list so we can use the __eq__ method of it here.
        return self.components == other.components

    def __ne__(self, other):
        # Reuse the code from the equality overload then flip the result
        return not self == other

    def __getitem__(self, item):
        # Called when using this class like a list
        return self.components[item]

    def __contains__(self, item):
        # This is called with keywords such as "in"
        return item in self.components

    def __len__(self):
        # This is called when the len built in function is passed a Vector
        return len(self.components)

    def __iter__(self):
        # Use the list's iterator so we don't have to write our own
        # Used for things like for loops
        return iter(self.components)

    def __str__(self):
        # String representation of the vector
        return "{}".format(self.components)


if __name__ == "__main__":
    vec1 = Vector([1,2,3])
    vec2 = Vector([9,8,7])

    print("Addition: {}".format(vec1 + vec2))
    print("Subtraction: {}".format(vec2 - vec1))
    print("Size of vec1: {}".format(len(vec1)))
    print("Does vec1 contain 5? {}".format(5 in vec1))
    print("Does vec2 contain 9? {}".format(9 in vec2))
    print("Dot product: {}".format(vec1 * vec2))
    print("Do vec1 and vec2 have the same elements? {}".format(vec1 == vec2))
    print("Is vec2 not equal to itself? {}".format(vec2 != vec2))
    print("Last element of vec1: {}".format(vec1[-1]))
René Sánchez
René Sánchez
9,954 Points

damn! that looks kinda advanced, but looks pretty great, I hope that i can code like that soon...or it isn't as complex as it looks?

either way, cool job man (Y)