pythonpython-3.xmethod-resolution-order

How fix MRO when you inherit int in python


I have in my code biiiig numbers, like quadrillions and quintillions. So I build a fancy converter for them

class Repr:
    def __str__(self):
        # magic
        return '123.456qa'
   
    def __repr__(self):
        for parent in self.__class__.__mro__:
            if parent in [self.__class__, Repr]:
                continue
            return f'{self.__class__.__name__}' \
                   f'({parent.__repr__(self)})'
        raise ValueError('how this is possible?')

Now I am trying to use it

class MyValue(Repr, int):
    pass

v = MyValue(123.4*10**12)
print(v)         # expected '123.4t'
print(f'{v!r}')  # expected 'MyValue(123400000000000)'

What I fail to understand - is how MRO works if I switch parents class MyValue(int, Repr)

According to all known documentation, this should behave as int. Because int is first, int has both __repr__ and __str__.

That is true in the case of converting to string

class MyValue(int, Repr):
    pass

v = MyValue(123.4*10**12)
print(f'{v!r}')  # expected '123400000000000'

Debug shows, that Repr.__repr__ is not even used.

BUT! Repr.__str__ is used!

print(v)         # expected `123400000000000`
'123.4t'         # actual result

Why do we have so much inconsistency? Why is this behavior not according to documentation?


Solution

  • int only defines its own __repr__, not its own __str__. It inherits __str__ from object. When you define class MyValue(int, Repr), Repr comes before object in the MRO, so Repr.__str__ gets used instead.