Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python class that extends int doesn't entirely behave like an int

Tags:

python

I'm seeing some weird behavior when trying to convert a string to a class I wrote that extends int. Here's a simple program that demonstrates my problem:

class MyInt(int):
    pass

toInt = '123456789123456789123456789'

print "\nConverting to int..."
print type(int(toInt))

print "\nConverting to MyInt..."
print type(MyInt(toInt))

Since MyInt is empty, I expected that it would behave exactly like an int. Instead, here's the output I got from the program above:

Converting to int...
<type 'long'>

Converting to MyInt...
Traceback (most recent call last):
  File "int.py", line 9, in <module>
    print type(MyInt(toInt))
OverflowError: long int too large to convert to int

The string can't convert to a MyInt! What about the way I wrote MyInt causes it to behave differently than its base class? In this case, there seems to be some kind of maximum on MyInt; are there other properties that get implicitly imposed like this when a built-in class is extended in Python? And, finally, is there a way to change MyInt so that it doesn't have this maximum anymore?

like image 247
dshapiro Avatar asked May 23 '12 17:05

dshapiro


People also ask

What is Type class int in Python?

int is a class. The type of a class is usually type . And yes, almost all classes can be called like functions. You create what's called an instance which is an object that behaves as you defined in the class. They can have their own functions and have special attributes.

Is int () a function or a method?

The int() function converts the specified value into an integer number. The int() function returns an integer object constructed from a number or string x, or return 0 if no arguments are given.

Is int () a function call?

Pedantically speaking, int itself is a class, which is a callable object, and when you call a class that call gets automatically converted into a call to the class's constructor method (that is, its __new__ method). But informally it's common to refer to int() as a function call or method call.

Is int a constructor in Python?

The constructors int() , float() , and complex() can be used to produce numbers of a specific type.


2 Answers

The secret is all in the __new__() method:

>>> class MyInt(int): pass
>>> MyInt.__new__ == int.__new__
True
>>> MyInt.__new__(MyInt, '123456789101234567890')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: Python int too large to convert to C long
>>> MyInt.__new__(int, '123456789101234567890')
123456789101234567890L

Basically when you instantiate a class the very first thing that happens (before __init__(self, *args)) is that __new__(cls, *args) is called. It is passed the class object as its first argument. The __new__ method for int (which is inherited by MyInt) only performs the conversion to long if the class it is passed is int. I assume this is to avoid messing up subclasses, since converted MyInt to long would remove all the special functionality you added.

You should use long as your base class if you want integers bigger than int can handle.

like image 128
Peter Avatar answered Sep 16 '22 12:09

Peter


Hopefully, this session with the interpreter will provide some insight as to what is happening:

>>> i = 1
>>> print type(i), i
<type 'int'> 1
>>> i = int((i << 31) - 1)
>>> print type(i), i
<type 'int'> 2147483647
>>> i += 1
>>> print type(i), i
<type 'long'> 2147483648
>>> 

Your class is not inheriting this behavior because Python probably treats int objects as a special case.

like image 21
Noctis Skytower Avatar answered Sep 18 '22 12:09

Noctis Skytower