Класс Python, который расширяет int, не полностью ведет себя как int
Я вижу какое-то странное поведение при попытке конвертировать строку в класс, который я написал, который расширяет int
. Вот простая программа, демонстрирующая мою проблему:
class MyInt(int):
pass
toInt = '123456789123456789123456789'
print "\nConverting to int..."
print type(int(toInt))
print "\nConverting to MyInt..."
print type(MyInt(toInt))
Так как MyInt
пусто, я ожидал, что он будет вести себя точно как int
. Вместо этого здесь вывод, полученный мной из программы выше:
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
Строка не может преобразовать в MyInt
! Как насчет того, как я написал MyInt
, заставляет его вести себя иначе, чем его базовый класс? В этом случае на MyInt
, по-видимому, есть какой-то максимум; существуют ли другие свойства, которые вводятся неявно, как это, когда встроенный класс расширен в Python? И, наконец, есть ли способ изменить MyInt
, чтобы он больше не имел этого максимума?
Ответы
Ответ 1
Секрет все в методе __new__()
:
>>> 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
В основном, когда вы создаете экземпляр класса, самое первое, что происходит (до __init__(self, *args)
), - это вызов __new__(cls, *args)
. В качестве первого аргумента передается объект класса. Метод __new__
для int
(который наследуется MyInt
) выполняет только преобразование в long
, если класс, который он передал, int
. Я предполагаю, что это необходимо, чтобы избежать перебора подклассов, поскольку преобразованный MyInt
в long
удалит все специальные функциональные возможности, которые вы добавили.
Вы должны использовать long
в качестве базового класса, если хотите, чтобы целые числа, превышающие int
, могли обрабатывать.
Ответ 2
Надеюсь, этот сеанс с интерпретатором даст некоторое представление о том, что происходит:
>>> 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
>>>
Ваш класс не наследует это поведение, потому что Python, вероятно, рассматривает объекты int
как частный случай.