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?
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.
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?
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
, orbytearray
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.