Я работаю над проблемой, поставленной этим сообщением: Быстрый способ удалить несколько элементов из списка/очереди
В основном все, что я хочу сделать, это реализовать цикл for в C. Цикл for должен получить доступ к генератору и уметь удалять элементы массива (и увеличивать целое число). Что-то во мне говорит мне, что это было бы тяжело сложно, но другая часть говорит, что это может быть обработано за несколько минут.
У меня нет опыта написания высокого уровня C (хотя я написал код для микроконтроллеров), а учебники для ctypes и другого c- > python кажутся, что они решают более сложные проблемы.
def forfilt():
marked = (i for i, x in enumerate(b) if tokeep(x))
shift = 0
for n in marked:
del b[n - shift]
shift += 1
Я задаю два вопроса:
Это сложно?
У вас есть указатели/вы хотите написать код самостоятельно?: D
Это кажется довольно важной проблемой для меня на самом деле. Я не знаю, как быстро выполнить то, что задавал первоначальный вопрос. Я полагаю, что если вы знаете ответ на этот вопрос, тогда вопрос недействителен.
Если вам нужно удалить служебные данные для цикла, достаточно указать тип переменной цикла for в Cython (pip install cython
). Здесь изменен remove_inplace_senderle2()
в Cython delitems.pyx
:
#cython: boundscheck=False, wraparound=False
import cython
@cython.locals(end=cython.Py_ssize_t, i=cython.Py_ssize_t)
def remove_inplace_senderle2(L, keep):
end = 0
for i in range(len(L)):
x = L[end] = L[i]
if keep(x):
end += 1
del L[end:]
for i in range(len(L))
переводится в классический C-loop: for (i=0; i < L_length; ++i)
, а его служебные данные затмеваются служебными служебными вызовами keep()
.
Примечание: вышеуказанная функция может быть медленнее в чистом Python, чем L = filter(keep, L)
(или listcomp).
Смотрите gcd()
функцию для еще более простого примера, как Cython можно скомпилировать и использовать.
Написание кода C на CPython C-API значительно приятнее, чем написание кода C без поддержки такого API. Тем не менее, это, прежде всего, процесс построения и компоновки и получения всего того, что может быть довольно утомительным. После того, как у вас есть расширение C на месте, добавление к нему не слишком сложно (хотя есть еще кое-какие возможности для того, чтобы сделать вещи правильно выставлены на уровне Python и убедиться, что все ваши ссылочные подсчеты верны).
Другие инструменты статической компиляции, такие как Cython, испытывают относительно высокие затраты на установку, чтобы получить скомпилированное расширение, работающее в первую очередь, но гораздо проще в использовании, если оно уже на месте.
В связи с вашим конкретным вопросом, сравнивая подход понимания списка к встроенному filter
(или его эквиваленту Py3k, functools.filter
), плакат связанного с вами вопроса уже продемонстрировал эффект отбрасывания кода цикла в C - натурный цикл является одним из основных преимуществ встроенных итерационных и редукционных функций, таких как sum
, any
, all
, map
и filter
.
Удаление накладных расходов цикла уровня Python, вероятно, отвечает за большую часть измеренной ~ 10% -ной разницы в производительности двух подходов (понимание списка и вызов фильтра).
Это зависит от того, насколько прост. Да, эта конкретная функция может быть записана как движение памяти на месте, пока входной сигнал является массивом.
size_t for_filt( my_struct *b, size_t n ) {
my_struct *src_pen, *dst_pen;
for ( src_pen = dst_pen = b;
src_pen != b + n;
++ src_pen ) {
if ( tokeep( src_pen ) ) {
memmove( dst_pen ++, src_pen, sizeof (my_struct) );
}
}
return dst_pen - b; /* return number of elements in resulting array */
}
Стандартная библиотека С++ уменьшает указанную выше функцию до однострочного:
n = std::remove_if( b, b+n, std::not1( tokeep ) ) - b;
Функция будет работать со структурами, кроме массивов, но n = … - b;
является специфичной для массива.