Search code examples
pythonbuilt-inenumerate

subclassing the builtin enumerate in python


Consider the code below. I am trying to subclass the builtin enumerate so that it prints a line for every turn of the for loop. The code seems to be working, which is surprising, because I have never called super().__init__(x). So, what is happening here? Who is initializing the base class enumerate the right way? Is there some magic from the __new__ method happening here?

class myenum(enumerate):
    def __init__(self,x):
        self.x_   = x
        self.len_ = len(x)
        
    def __next__(self):
        out = super().__next__()
        print(f'Doing {out[0]} of {self.len_}')
        return out

for ictr, key in myenum(['a','b','c','d','e']):
    print('Working...')

Solution

  • The __init__ method is always optional. All initialization of an instance can always be done purely in the __new__ method, which is the case for the enumerate class, whose __new__ method is defined here in the enum_new_impl function, where you can see that the iterable argument is stored as the attribute en_sit of the returning object en, of the struct type enumobject:

    static PyObject *
    enum_new_impl(PyTypeObject *type, PyObject *iterable, PyObject *start)
    {
        enumobject *en;
    
        ...
    
        en->en_sit = PyObject_GetIter(iterable);
    
        ...
    
        return (PyObject *)en;
    }