Ошибка сегментации Python?

Это генерирует Segmentation Fault: 11, и я не знаю, почему.

Прежде чем попасть в него, вот код:

import numpy.random as nprnd
import heapq
import sys

sys.setrecursionlimit(10**6)


def rlist(size, limit_low, limit_high):
    for _ in xrange(size): 
        yield nprnd.randint(limit_low, limit_high)

def iterator_mergesort(iterator, size):
    return heapq.merge(
         iterator_mergesort(
           (iterator.__next__ for _ in xrange(size/2)), size/2),
         iterator_mergesort(
            iterator, size - (size/2))
       )

def test():
    size = 10**3
    randomiterator = rlist(size, 0, size)
    sortediterator = iterator_mergesort(randomiterator, size)
    assert sortediterator == sorted(randomiterator)

if __name__ == '__main__':
    test()

В принципе, это просто слияние, которое работает на итераторах и выражениях генератора вместо работы над списками, чтобы минимизировать объем памяти в любой момент времени. Это ничего особенного и использует встроенный метод heapq.merge() для слияния итераторов, поэтому я был очень удивлен, когда все ломается.

Запуск кода быстро дает Segmentation Fault: 11 и окно с ошибкой, сообщающее, что python разбился. Я понятия не имею, где искать или как отлаживать этот, так что любая помощь будет очень оценена.

Ответ 1

Segmentation Faults в python происходит по одной из двух причин:

У вас закончилась нехватка памяти

Ошибка в модуле C

Здесь seg-ошибка принадлежит первому. У вас (I) есть безграничная рекурсия, потому что в iterator_mergesort() нет базового аргумента, он будет постоянно называть себя вечно.

Обычно python генерирует исключение для этого, и оно завершается перед вызовом segfault. Тем не менее, предел рекурсии был установлен чрезвычайно высоким, поэтому у python заканчивается память и ломается до того, как он распознает, что он должен генерировать исключение для неограниченной рекурсии.

Добавьте базовый пример:

...
def iterator_mergesort(iterator, size):
return heapq.merge(
         iterator_mergesort(
           (iterator.next() for _ in xrange(size/2)), size/2),
         iterator_mergesort(
            iterator, size - (size/2))
       ) if size >= 2 else iterator #<-- Specifically this

Теперь он передает функцию test() и сортирует, хотя и довольно медленно.