Convert custom objects to int with explicit base

Question:

Let’s say we have the following class:

class Foo:
    def __init__(self):
        self.bar = "12"

    def __str__(self):
        return self.bar
    
    def __int__(self, *args, **kwargs):
        print("inside __int__")
        return int(self.bar, *args, **kwargs)


a = Foo()
print(int(a))
# -> inside __int__
# -> 12

The result of printing this is as you would expect. However if we try:

print(int(a, 10))   # or any other valid base instead of 10

the following exception is raised:

TypeError: int() can't convert non-string with explicit base

Also, inside __int__ is not printed meaning that a.__int__ is not called. Is there any special method which would allow specifying a base in the int() call or do I just have to live with this behavior?

Even more interesting (and more in the direction of what I want to do) is the following:

class Foo(str):   # subclass of str and excepts argument in constructor
    def __init__(self, bar):
        self.bar = bar

    def __int__(self, *args, **kwargs):
        return int(self.bar, *args, **kwargs)


a = Foo("12")
print(int(a), int(a, 10))
# -> 12 12
# Actually works

a.bar = "34"
print(int(a), int(a, 10))
# -> 34 12
# what?

My assumption on this one is that int(num, base) uses num.__getnewargs__(). Either way, is there any way to get around these examples?

Asked By: Mr_HxID

||

Answers:

This behaviour is specifically called out in the documentation of int:

If x is not a number or if base is given, then x must be a
string, bytes, or bytearray instance representing an integer
literal in radix base.

The __int__ "magic method" (or __index__, __trunc__ which are used as fallbacks) is only invoked when the base argument is not provided.

Answered By: jonrsharpe
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.