Magic Methods in Python are a collection of methods that are automatically associated with every class definition in the language. If you create your own classes, you can override one or more standard magic methods to customize their behavior. There are many magic methods in Python, and we include a table of them at the end of this tutorial. For now, we want to take a look at some of the more commonly used magic methods which can be useful in day to day programming. Magic methods can be used to customize how your objects are represented as strings, control how attributes are accessed on an object during getting and setting, check for equality, and to make an object callable like a function.
String Representation
The first two magic methods that we’re going to learn about are the ones that Python uses to generate string representations of objects. One is called __str__ and the other is called __repr__. The __str__ function is used to output a user-friendly string description of the object and is usually intended to be displayed to the user. The __repr__ function is used more for the developer of the software. It outputs a string that can be used for debugging purposes, so it gets used to display a lot of detailed information. These functions get invoked on an object in a variety of ways. When you call the print() function and pass in the object, or when you use the __str__ or __repr__ casting functions, these methods will get called.
__str__ and __repr__
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
class Book(): def __init__(self, title, author, price): super().__init__() self.title = title self.author = author self.price = price # The __str__ function is used to return a user-friendly string # representation of the object def __str__(self): return f'{self.title} by {self.author}, costs {self.price}' # The __str__ function is used to return a developer-friendly string # representation of the object def __repr__(self): return f'title={self.title},author={self.author},price={self.price}' book1 = Book('Python Crash Course', 'Eric Matthes', 23.99) book2 = Book('Serious Python', 'Julien Danjou', 25.43) # print each object print(book1) print(book2) # use str() and repr() print(str(book1)) print(repr(book2)) |
Python Crash Course by Eric Matthes, costs 23.99 Serious Python by Julien Danjou, costs 25.43 Python Crash Course by Eric Matthes, costs 23.99 title=Serious Python,author=Julien Danjou,price=25.43
Equality and Comparison
By using the equality and comparison magic methods, we can give objects the ability to compare themselves to each other. The magic method named eq, gets called on your object when it is compared to another object. The code below also implements the greather than or equal to magic method and the less than magic method.
__eq__ __ge__ __lt__
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
class Book(): def __init__(self, title, author, price): super().__init__() self.title = title self.author = author self.price = price def __eq__(self, value): if not isinstance(value, Book): raise ValueError('Can't compare book to non-book type') return (self.title == value.title and self.author == value.author and self.price == value.price) def __ge__(self, value): if not isinstance(value, Book): raise ValueError('Can't compare book to non-book type') return self.price >= value.price def __lt__(self, value): if not isinstance(value, Book): raise ValueError('Can't compare book to non-book type') return self.price < value.price book1 = Book('Python Crash Course', 'Eric Matthes', 23.99) book2 = Book('Serious Python', 'Julien Danjou', 25.43) book3 = Book('Automate the Boring Stuff with Python', 'Al Sweigart ', 26.99) book4 = Book('Python for Kids', 'Jason Briggs', 19.79) # Check for equality print(book1 == book3) print(book1 == book2) print(book3 == book3) # Check for greater and lesser value print(book2 >= book1) print(book2 < book1) print(book3 >= book2) # Sorting books books = [book1, book3, book2, book4] books.sort() print([book.title for book in books]) |
False False True True False True ['Python for Kids', 'Python Crash Course', 'Serious Python', 'Automate the Boring Stuff with Python']
Attribute Access
Python’s magic methods also give you complete control over how an object’s attributes are accessed. A class can define methods that intercept the process any time an attribute is set or retrieved. The methods we’ll look at in the section are as follows.
- __getattribute__ Called when an attribute is retrieved. Be aware that you can’t directly access the attr name otherwise a recursive loop is created
- __setattr__ called when an attribute value is set. Don’t set the attr directly here otherwise a recursive loop causes a crash
- __getattr__ called when __getattribute__ lookup fails – you can generate attributes on the fly with this method
__getattribute__ __setattr__ __getattr__
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
class Book(): def __init__(self, title, author, price): super().__init__() self.title = title self.author = author self.price = price self._discount = 0.1 def __str__(self): return f'{self.title} by {self.author}, costs {self.price}' def __getattribute__(self, name): if (name == 'price'): price = super().__getattribute__('price') discount = super().__getattribute__('_discount') return price - (price * discount) return super().__getattribute__(name) def __setattr__(self, name, value): if (name == 'price'): if type(value) is not float: raise ValueError('The "price" attribute must be a float') return super().__setattr__(name, value) def __getattr__(self, name): return name + ' is not here!' book1 = Book('Python Crash Course', 'Eric Matthes', 23.99) book2 = Book('Serious Python', 'Julien Danjou', 25.43) # Try setting and accessing the price book1.price = 37.95 print(book1) book2.price = float(40) # using an int will raise an exception print(book2) # If an attribute doesn't exist, __getattr__ will be called print(book1.randomprop) |
Python Crash Course by Eric Matthes, costs 34.155 Serious Python by Julien Danjou, costs 36.0 randomprop is not here!
Make An Object Callable
The __call__ magic method has the interesting ability to make an object callable just like you would call any other function in Python.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class Book(): def __init__(self, title, author, price): super().__init__() self.title = title self.author = author self.price = price def __str__(self): return f'{self.title} by {self.author}, costs {self.price}' def __call__(self, title, author, price): self.title = title self.author = author self.price = price book1 = Book('Python Crash Course', 'Eric Matthes', 23.99) book2 = Book('Serious Python', 'Julien Danjou', 25.43) # call the object as if it were a function print(book1) book1('Learning Python', 'Mark Lutz', 44.94) print(book1) |
Python Crash Course by Eric Matthes, costs 23.99 Learning Python by Mark Lutz, costs 44.94
Python Magic Methods Reference
Initialization and Construction | What It Does |
---|---|
__new__(cls, other) | Allows us to override the New Step of any object via the __new__ magic method |
__init__(self, other) | When an object is created, it is initialized by calling the __init__ method on the object |
__del__(self) | __del__ is a destructor method which is called as soon as all references of the object are deleted i.e when an object is garbage collected |
Unary operators and functions | What It Does |
---|---|
__pos__(self) | Implements behavior for unary positive (e.g. +some_object) |
__neg__(self) | Implements behaviour for when the unary – operator is called on our object |
__abs__(self) | Is called by built-in abs() function. It removes negative sign from a number (if it is negative) |
__invert__(self) | Uses the ~ operator. It is the “invert” or “complement” operation, in which all the bits of the input data are reversed |
__round__(self,n) | Implements behavior for the round() function. Returns a floating point number that is a rounded version of the specified number |
__floor__(self) | Implements the built-in math.floor() function |
__ceil__(self) | ceil() returns the ceiling value of x i.e., the smallest integer not less than x |
__trunc__(self) | Removes any decimals is what math.trunc() does |
Augmented Assignment | What It Does |
---|---|
__iadd__(self, other) | addition with assignment: a +=b |
__isub__(self, other) | subtraction with assignment: a -=b |
__imul__(self, other) | multiplication with assignment: a *=b |
__ifloordiv__(self, other) | integer division with assignment: a //=b |
__idiv__(self, other) | division with assignment: a /=b |
__itruediv__(self, other) | true division with assignment |
__imod__(self, other) | modulo with assignment: a%=b |
__ipow__(self, other) | exponentswith assignment: a **=b |
__ilshift__(self, other) | left bitwise shift with assignment: a<<=b |
__irshift__(self, other) | right bitwise shift with assignment: a >>=b |
__iand__(self, other) | bitwise AND with assignment: a&=b |
__ior__(self, other) | bitwise OR with assignment: a|=b |
__ixor__(self, other) | bitwise XOR with assignment: a ^=b |
Type Conversion | What It Does |
---|---|
__int__(self) | int() method to convert a type to an int |
__float__(self) | float() method to convert a type to float |
__complex__(self) | complex() method to convert a type to complex |
__oct__(self) | oct() method to convert a type to octal |
__hex__(self) | hex() method to convert a type to hexadecimal |
__index__(self) | Implements type conversion to an int when the object is used in a slice expression |
__trunc__(self) | To get called from math.trunc() method |
String Magic Methods | What It Does |
---|---|
__str__(self) | str() method to return a string representation of a type |
__repr__(self) | repr() method to return a machine readable representation of a type |
__unicode__(self) | unicode() method to return an unicode string of a type |
__format__(self, formatstr) | string.format() method to return a new style of string |
__hash__(self) | hash() method to return an integer |
__nonzero__(self) | bool() method to return True or False |
__dir__(self) | dir() method to return a list of attributes of a class |
__sizeof__(self) | sys.getsizeof() method to return the size of an object |
Attribute Magic Methods | What It Does |
---|---|
__getattr__(self, name) | called when the accessing attribute of a class that does not exist |
__setattr__(self, name, value) | called when assigning a value to the attribute of a class |
__delattr__(self, name) | called when deleting an attribute of a class |
Operator Magic Methods | What It Does |
---|---|
__add__(self, other) | add operation using + operator |
__sub__(self, other) | subtraction operation using – operator |
__mul__(self, other) | multiplication operation using * operator |
__floordiv__(self, other) | floor division operation using // operator |
__div__(self, other) | division operation using / operator |
__mod__(self, other) | modulo operation using % operator |
__pow__(self, other[, modulo]) | calculating the power using ** operator |
__lt__(self, other) | comparison using < operator |
__le__(self, other) | comparison using <= operator |
__eq__(self, other) | comparison using == operator |
__ne__(self, other) | comparison using != operator |
__ge__(self, other) | comparison using >= operator |