Python Extend Subclass Overload Built-In Int or List Class and object creation using Int() Brackets vs List()

56 views Asked by At

Python Version = 3.9.6 IDE = vscode

Hi Folks, forgive me if i dont use the right terminology/nomenclature. Could really use your help with the following:

Im trying to subclass/extended/overload the built in "int" and "list" classes.

However, depending on how i define a integer variable with either direct assignment or int(), my extended method toString() will only work if i applied int().

The same happens with list(). It also depending on how the list object was created with [] or list() and only works with list().

Why DONT the variables 'b' and 'd' in my code below have access to the toString() methods ?

Thanks for your help in advance.

class int(int):
     def __new__(cls, value): return super().__new__(cls, value)
     def toString(self) -> str: return str(self)

c = int(8)
d = 8

print(c.toString())
print(d.toString())     # Error: 'int' object has no attribute 'toString'


class list(list):
     def __init__(self, li): super(list, self).__init__(li)
     def toString(self) -> str: return ' '.join(str(x) for x in self)

a = list([1,2,3])
b = [1,2,3]

print(a.toString()) 
print(b.toString())   # Error: 'list' object has no attribute 'toString'
2

There are 2 answers

4
Codeman On

The problem is that int and list are python types. When you say d=8, python makes it an int in the python built-ins. Making a int(8) however isn't overrided. Similar logic can be applied to your list object too.

2
Egeau On

This is something you cannot do in python. It is a concious decision by the language designers to not allow for overwriting of buildins. (Because, tough you might think of it as extending or as adding features, what you are doing is overwriting a default class with a custom class.)

The argument is that, if [1, 2, 3] is suddenly something else, or behaves slightly differently because something is imported, it breaks the stability of code.

What you appear to be looking for is a feature like Scala's Extension methods, especially as you called the function toString instead of to_string but this simply does not exist in Python. (alternatively, this is quite similar to Ruby's class reopening, or the trait system of the ML language family.)

What you have right now, simply creating a wrapper type, is the "correct" way to do something like this in python, and the way you should be doing this if you're still learning the language. You should, though, rename the wrapper to something other than int (like StringableInt or whatever), and then simply use the class constructor every time you want features from it, and inheriting from numbers.Integral, or at least registering with it (Integral.register(StringableInt))

I should mention that it is possible with an external library, though, the one I know is extype, meaning it should also be possible, if ugly, in default python.

In short: you shouldn't make your toString (please rename it to to_string) available for buildin types, and the language is actively preventing you from doing this. Tough it is possible, you should use the (renamed) wrapper class you are using right now,