четверг, 20 января 2011 г.

Python xrange и OverflowError

sic! Данная проблема присуща Python версии 2.х. Счастливым обладателям интерпретатора Python версии 3.х можно дальше не читать.

Простой пример
Представьте себе, бывает и такое. Осталось выяснить, почему. Давайте взглянем на пример кода, который приводит к такой ошибке. Пример довольно простой:
for i in xrange(100000000000):
print i
Приводит этот пример к следующей ошибке:
OverflowError: long int too large to convert to int

Поэкспериментируем
Ладно, не хочет Python так, - попробуем совершенно дурацкую мысль - заменить xrange на range:
for i in range(100000000000):
В результате получаем еще одну интересную (как и стоило ожидать) ошибку:
OverflowError: range() result has too many items
Не хочет, хороняка, он создавать такой длинный список. Исходя из вышеизреченных интерпретатором ошибок, мы узнаем несколько интересных (для кого-то, может и неинтересных) фактов о Python:
  1. Максимальная длина списка в Python = sys.maxint, то бишь - 2147483647.
  2. xrange для создания итератора принимает числа <= sys.maxint.
  3. Если вы подумали, что сможете создать список длиной sys.maxint, - вы ошиблись =). Я, например, получил еще одну забавную и очень лаконичную ошибку:
MemoryError
Ну не влезает он в память, хоть ты тресни.

Продолжаем искать
Первая мысль, естественно, - баг. Смотрим, ищем, находим. А по ссылке мы находим баг, который добрый человек запостил в багтрекер Python. И опять - облом. Мудрый разработчик объясняет, что, мол, нехорошо такие длинные итерации делать, ибо неоптимизировано и нифига не быстро, и это вообще не баг, а фича, и не будем мы его фиксить.

Очевидное решение
Ну, решение действительно очевидное: обратимся к старому доброму циклу while, при этот получив нужный результат (стоит заметить, работающий гораздо медленнее, нежели xrange):
number = sys.maxint + 10000
while number > 0:
number -= 1
При этом интерпретатор долго будет думать, но, хотя бы, получили рабочий код.

2 комментария:

  1. Да здравствует Python 3 с бесконечно длинным int :)

    ОтветитьУдалить
  2. Очень ценное замечание, добавлю пометку в пост, как-то вылетело из головы ))

    ОтветитьУдалить

В этом гаджете обнаружена ошибка