Это просто реализовать простую функцию Python в C?

1

Я работаю над проблемой, поставленной этим сообщением: Быстрый способ удалить несколько элементов из списка/очереди

В основном все, что я хочу сделать, это реализовать цикл 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

Это кажется довольно важной проблемой для меня на самом деле. Я не знаю, как быстро выполнить то, что задавал первоначальный вопрос. Я полагаю, что если вы знаете ответ на этот вопрос, тогда вопрос недействителен.

  • 1
    Почему вы думаете, что C будет быстрее, чем собственный код Python?
  • 0
    потому что циклы for заведомо медленные, и это не может быть решено сжатием.
Показать ещё 3 комментария
Теги:
for-loop
ctypes

3 ответа

3
Лучший ответ

Если вам нужно удалить служебные данные для цикла, достаточно указать тип переменной цикла 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 можно скомпилировать и использовать.

  • 0
    эй, спасибо большое. Это именно тот вопрос, который я задавал, и решение кажется простым и питонным: D
2

Написание кода C на CPython C-API значительно приятнее, чем написание кода C без поддержки такого API. Тем не менее, это, прежде всего, процесс построения и компоновки и получения всего того, что может быть довольно утомительным. После того, как у вас есть расширение C на месте, добавление к нему не слишком сложно (хотя есть еще кое-какие возможности для того, чтобы сделать вещи правильно выставлены на уровне Python и убедиться, что все ваши ссылочные подсчеты верны).

Другие инструменты статической компиляции, такие как Cython, испытывают относительно высокие затраты на установку, чтобы получить скомпилированное расширение, работающее в первую очередь, но гораздо проще в использовании, если оно уже на месте.

В связи с вашим конкретным вопросом, сравнивая подход понимания списка к встроенному filter (или его эквиваленту Py3k, functools.filter), плакат связанного с вами вопроса уже продемонстрировал эффект отбрасывания кода цикла в C - натурный цикл является одним из основных преимуществ встроенных итерационных и редукционных функций, таких как sum, any, all, map и filter.

Удаление накладных расходов цикла уровня Python, вероятно, отвечает за большую часть измеренной ~ 10% -ной разницы в производительности двух подходов (понимание списка и вызов фильтра).

2

Это зависит от того, насколько прост. Да, эта конкретная функция может быть записана как движение памяти на месте, пока входной сигнал является массивом.

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; является специфичной для массива.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню