Это просто реализовать простую функцию Python в C? - PullRequest
1 голос
/ 23 апреля 2011

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

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

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

Ответы [ 3 ]

3 голосов
/ 24 апреля 2011

Если все, что вам нужно, это удалить служебные данные цикла for, тогда достаточно определить тип переменной цикла 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-цикл: for (i=0; i < L_length; ++i), и его издержки уменьшаются из-за издержек вызова функции keep().

Примечание: вышеуказанная функция может быть медленнее в чистом Python, чем L = filter(keep, L) (или listcomp).

См. gcd() function для еще более простого примера того, как Cython может быть скомпилирован и использован.

2 голосов
/ 24 апреля 2011

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

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

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

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

2 голосов
/ 23 апреля 2011

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

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 */
}

Стандартная библиотека C ++ сводит указанную выше функцию к одной строке:

n = std::remove_if( b, b+n, std::not1( tokeep ) ) - b;

Функция будет работать со структурами, кроме массивов, но n = … - b; зависит от массива.

...