Special methods#

A class can hold methods that define its behavior in common cases in Python. These methods usually start and end with double underscores (__<name>__).

Indexing#

There are three methods that organise how the class would behave when the indexing operator [] is applied to the instance: __getitem__, __setitem__, __delitem__. Their names clearly describe the idea behind them.


The next cell shows the implementation of the class that shows the appropriate information for each of the methods.

class Test:
    def __setitem__(self, key, value):
        print(f"Set item called with {key} - {value}")
    
    def __getitem__(self, key):
        print(f"getitem is called with {key}")
        return "dummy item"
    
    def __delitem__(self, key):
        print(f"delitem is called with {key}")

And here is the creation of the instance and all the manipulations that trigger the methods that we are now focusing on.

test = Test()

test[40] = 4
print(test["wow"])
del test[3.14]
Set item called with 40 - 4
getitem is called with wow
dummy item
delitem is called with 3.14

Note: if you want to handle slices in your objects just write code to handle python slice object. The following code passes 3: to the indexing operator.

Test()[3:]
getitem is called with slice(3, None, None)
'dummy item'

The result there is the slice object passed to the corresponding method.

Iteration protocol#

To organise ability to iterate over your object you basically need to define the __iter__ method. It will be called each time the object is passed to the iter build in function or used in for cycle.

The returned object is typically have __next__. This method is called on every iteration. In particular case __iter__ can return self, but for that case __next__ have to be defined in the class.

Note: python understands when to stop iteration by raising StopIteration exception. So you need to raise it inside the __next__ method when object needs to stop iterations according to your logic.

Check more at corresponding iterator section of the official documentation.


The following cell implements the class that will have the specified during creation number of iterations.

class IterationExample:
    
    def __init__(self, max_iterations):
        self.iteration = 0
        self.max_iterations = max_iterations

    def __iter__(self):
        print("__iter__ is called")
        return self
    
    def __next__(self):
        print("__next__ is called")

        if self.iteration >= self.max_iterations:
            print("Stop iteration is raised")
            raise StopIteration
        
        self.iteration += 1
        return self.iteration

Now apply the for cycle to the instance of that class.

for i in IterationExample(3):
    pass
__iter__ is called
__next__ is called
__next__ is called
__next__ is called
__next__ is called
Stop iteration is raised

Note __iter__ that retuns objects that do’t implement __next__ make no sence, as python checks this detail.

class Fail:
    def __iter__(self):
        return self

iter(Fail())
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[50], line 5
      2     def __iter__(self):
      3         return self
----> 5 iter(Fail())

TypeError: iter() returned non-iterator of type 'Fail'

Switch number system#

There is a special __index__ special method that determines the behaviour of the object if programm tries to apply bin, oct or hex fucntions to it. __index__ just have to return regular python integer and converting of that number to the corresponding number system will be the result.


The following cell defines the class that returns from the index number specified in the constructor of the object.

class NSTest:
    def __init__(self, my_number):
        self.my_number = my_number
    
    def __index__(self):
        return self.my_number

The following code shows the result for different number systems and input numbers.

bin(NSTest(3))
'0b11'
oct(NSTest(10))
'0o12'
hex(NSTest(12))
'0xc'