2014-09-03 3 views
3

Реализация bytes.join метод, реализованный here включает в себя код, который защищает от изменения размера во время итерации:Изменение размера последовательности питона во время итерации

if (seqlen != PySequence_Fast_GET_SIZE(seq)) { 
     PyErr_SetString(PyExc_RuntimeError, 
         "sequence changed size during iteration"); 
     goto error; 
    } 

Как можно изменить итератор последовательность внутри bytes.join вызова и почему выше код необходимо? Или, может быть, это не нужно и лишнее?

+0

Почему вы хотите изменить размер последовательности во время ее повтора? Вероятно, это плохая идея. Покажите нам свой код, возможно, есть лучший способ. –

+0

Меня интересует, почему упомянутый фрагмент кода находится в реализации метода «join», вот и все. – pbp

+0

Является ли это основным C-кодом для 'str.join' Python? Как должен выглядеть результат «join», если последовательность меняется? Во всяком случае, строки неизменяемы, поэтому их последовательность байтов не должна меняться в первую очередь ... –

ответ

7

Если вы передадите объект списка bytes.join(), вы можете добавить элементы в список в другом потоке, а вызов bytes.join() - итерация.

Метод bytes.join() должен сделать два прохода над последовательностью; один раз, чтобы вычислить общую длину объектов, содержащихся, второй раз, чтобы затем построить фактический результат bytes. Изменение количества элементов во время итерации над ним поместило бы гаечный ключ в этот расчет.

Вы обычно не могли бы сделать это в список как GIL не освобожден, но если какой-либо из объектов в списке неbytes объекты, с которыми buffer protocol используется вместо этого. Как a comment on the original patch states:

Проблема с подхода заключается в том, что последовательность может быть мутировал, а другой поток работает (_getbuffer() может освободить GIL). Тогда предварительно вычисленный размер становится неправильным.

+0

Не '__getitem__' - последовательность, как гарантируется, является кортежем или списком благодаря PySequence_Fast. Темы, которые не уважают GIL, могут быть проблемой, но большинство кодов предполагает, что такие потоки не будут мешать их работе. Я склонен обвинять вызов '_getbuffer'; Я считаю, что позволяет элементам последовательности запускать произвольный код. – user2357112

+0

@ user2357112: Да, я пытался создать футляр и обнаружил, что произвольные последовательности сначала превращаются в список, а в подклассах списков их «__getitem__» обходит. Интерфейс буфера также здесь не помогает, так как для этого требуется доступ к C API. –

+0

@ user2357112: Другими словами, это только проблема для C-кода, сбрасывающего объект списка или потоки. –

Смежные вопросы