Класс Python, который расширяет int, не полностью ведет себя как int - программирование
Подтвердить что ты не робот

Класс 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, чтобы он больше не имел этого максимума?

4b9b3361

Ответ 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 как частный случай.