Magic Methods
Magic Methods
Magic Methods
Magic methods are special methods which have double underscores at the beginning and end of their
names.
They are also known as dunders.
So far, the only one we have encountered is __init__, but there are several others.
They are used to create functionality that can't be represented as a normal method.
class Vector2D:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector2D(self.x + other.x, self.y + other.y)
first = Vector2D(5, 7)
second = Vector2D(3, 9)
result = first + second
print(result.x)
print(result.y)
Result: >>>
8
16
>>>
The __add__ method allows for the definition of a custom behavior for the + operator in our class.
As you can see, it adds the corresponding attributes of the objects and returns a new object, containing
the result.
Once it's defined, we can add two objects of the class together.
Magic Methods
class SpecialString:
def __init__(self, cont):
self.cont = cont
spam = SpecialString("spam")
hello = SpecialString("Hello world!")
print(spam / hello)Try It Yourself
Result: >>>
spam
============
Hello world!
>>>
In the example above, we defined the division operation for our class SpecialString.
Result: >>>
spam
============
Hello world!
>>>
In the example above, we defined the division operation for our class SpecialString.
Magic Methods
class SpecialString:
def __init__(self, cont):
self.cont = cont
spam = SpecialString("spam")
eggs = SpecialString("eggs")
spam > eggsTry It Yourself
Result: >>>
>spam>eggs
e>spam>ggs
eg>spam>gs
egg>spam>s
eggs>spam>
>>>
As you can see, you can define any custom behavior for the overloaded operators.
Magic Methods
There are several magic methods for making classes act like containers.
__len__ for len()
__getitem__ for indexing
__setitem__ for assigning to indexed values
__delitem__ for deleting indexed values
__iter__ for iteration over objects (e.g., in for loops)
__contains__ for in
There are many other magic methods that we won't cover here, such as __call__ for calling objects as
functions, and __int__, __str__, and the like, for converting objects to built-in types.
Example:
import random
class VagueList:
def __init__(self, cont):
self.cont = cont
def __len__(self):
return random.randint(0, len(self.cont)*2)
Result: >>>
6
7
D
C
>>>
We have overridden the len() function for the class VagueList to return a random number.
The indexing function also returns a random item in a range from the list, based on the expression.
Object Lifecycle
The lifecycle of an object is made up of its creation, manipulation, and destruction.
The first stage of the life-cycle of an object is the definition of the class to which it belongs.
The next stage is the instantiation of an instance, when __init__ is called. Memory is allocated to store
the instance. Just before this occurs, the __new__ method of the class is called. This is usually
overridden only in special cases.
After this has happened, the object is ready to be used.
Other code can then interact with the object, by calling functions on it and accessing its attributes.
Eventually, it will finish being used, and can be destroyed.
Object Lifecycle
When an object is destroyed, the memory allocated to it is freed up, and can be used for other
purposes.
Destruction of an object occurs when its reference count reaches zero. Reference count is the number
of variables and other elements that refer to an object.
If nothing is referring to it (it has a reference count of zero) nothing can interact with it, so it can be
safely deleted.
In some situations, two (or more) objects can be referred to by each other only, and therefore can be
deleted as well.
The del statement reduces the reference count of an object by one, and this often leads to its deletion.
The magic method for the del statement is __del__.
The process of deleting objects when they are no longer needed is called garbage collection.
In summary, an object's reference count increases when it is assigned a new name or placed in a
container (list, tuple, or dictionary). The object's reference count decreases when it's deleted with del,
its reference is reassigned, or its reference goes out of scope. When an object's reference count reaches
zero, Python automatically deletes it.
Example: a = 42 # Create object <42>
b = a # Increase ref. count of <42>
c = [a] # Increase ref. count of <42>