pythonstringinheritancereprrecursionerror

RecursionError when inheriting from float and using str and repr


I was testing some features in Python for fun ;) But I have a recursion error that I don't understand

class Test(float):
    def __new__(cls, value):
        return super().__new__(cls, value)

    def __str__(self):
        return super().__str__()
    
    def __repr__(self):
        return f'<value: {str(self)}>'


test = Test(12)
print(test)

Traceback:

Traceback (most recent call last):
  File "C:\temp\test_float.py", line 13, in <module>
    print(test)
  File "C:\temp\test_float.py", line 6, in __str__
    return super().__str__()
  File "C:\temp\test_float.py", line 9, in __repr__
    return f'<value: {str(self)}>'
  File "C:\temp\test_float.py", line 6, in __str__
    return super().__str__()
  File "C:\temp\test_float.py", line 9, in __repr__
    return f'<value: {str(self)}>'
...the above 2 errors repeated many times...
  File "C:\temp\test_float.py", line 6, in __str__
    return super().__str__()
RecursionError: maximum recursion depth exceeded

The line return super().__str__() should call float.__str__() and just returns '12'.

Do you have any ideas ?


Solution

  • The core issue is that float.__str__(self) will call self.__repr__() rather than float.__repr__(self).

    Not only does that mean that you have an infinite recursion from Test.__repr__ to Test.__str__ to float.__str__ back to Test.__repr__, it means that Test.__str__ is going to print the same thing as Test.__repr__, which I assume you don't want since you went to the effort of reimplementing it.

    Instead I think you want:

    class Test(float):
        def __str__(self):
            return super().__repr__()
        
        def __repr__(self):
            return f'<value: {super().__repr__()}>'