0

A working solution, which returns integers, was given in Overload int() in Python.

However, it works only for returning int, but not float or let's say a list:

class Test:
    def __init__(self, mylist):
        self.mylist = mylist
    def __int__(self):
        return list(map(int, self.mylist))

t = Test([1.5, 6.1])
t.__int__()   # [1, 6]
int(t)

Thus t.__int__() works, but int(t) gives TypeError: __int__ returned non-int (type list).

Thus, is there a possibility to fully overwrite int, maybe with __getattribute__ or metaclass?

  • 1
    The method `__int__` is a toInt so it should return an int not a list – azro Apr 05 '20 at 12:24
  • 1
    The idea of `int`, `str`, etc. is that they call the underlying `__int__`, `__str__`, and perform this typecheck. By contract `str(..)` should return an instance of a `string`. – Willem Van Onsem Apr 05 '20 at 12:24
  • 1
    ``__int__`` does not overwrite ``int``. The method is a hook used by ``int`` when it does not understand its argument type. – MisterMiyagi Apr 05 '20 at 12:38
  • This does not make any sense. **The point** of `__int__` is to explain how to convert an instance of the class **to an integer**. You get this `TypeError` because you are trying to use the function for a fundamentally wrong and confused purpose. There is **no reason to expect** that returning something other than an integer from `__int__` would work, and **no sensible way to say** what it should mean if you could. – Karl Knechtel Apr 07 '23 at 10:53
  • `int`, meanwhile, **is the class itself** that integers belong to - **not** a function. It gets to decide what is returned when you call the class, and like most normal classes, it only returns instances of the class. (Unlike most classes, it can return instances that already existed.) – Karl Knechtel Apr 07 '23 at 10:54
  • @KarlKnechtel The accepted answer shows that this question is not a duplicate, but seeks for a superior solution. My comment there also gives a use case. – Friedrich -- Слава Україні Apr 07 '23 at 18:00

2 Answers2

3

The __int__, __float__, ... special methods and various others do not overwrite their respective type such as int, float, etc. These methods serve as hooks that allow the types to ask for an appropriate value. The types will still enforce that a proper type is provided.

If required, one can actually overwrite int and similar on the builtins module. This can be done anywhere, and has global effect.

import builtins

# store the original ``int`` type as a default argument
def weakint(x, base=None, _real_int=builtins.int):
    """A weakly typed ``int`` whose return type may be another type"""
    if base is None:
        try:
            return type(x).__int__(x)
        except AttributeError:
            return _real_int(x)
    return _real_int(x, base)

# overwrite the original ``int`` type with the weaker one
builtins.int = weakint

Note that replacing builtin types may violate assumptions of code about these types, e.g. that type(int(x)) is int holds true. Only do so if absolutely required.

This is an example of how to replace int(...). It will break various features of int being a type, e.g. checking inheritance, unless the replacement is a carefully crafted type. A full replacement requires emulating the initial int type, e.g. via custom subclassing checks, and will not be completely possible for some builtin operations.

MisterMiyagi
  • 44,374
  • 10
  • 104
  • 119
1

From the doc of __int__

Called to implement the built-in functions complex(), int() and float(). Should return a value of the appropriate type.

Here your method return a list and not an int, this works when calling it explictly but not using int() which checks the type of what is returned by the __int__


Here is a working example of what if could be, even if the usage if not very pertinent

class Test:
    def __init__(self, mylist):
        self.mylist = mylist
    def __int__(self):
        return int(sum(self.mylist))
azro
  • 53,056
  • 7
  • 34
  • 70