Упаковка библиотеки C ++ в Python, обработка пользовательских типов - PullRequest
1 голос
/ 29 февраля 2012

В настоящее время я пишу приложение NLP на python, которое требует быстрой реализации POS-тегов. теггер имеет интерфейс оболочки c ++:

#include "POSTagger.h"

extern "C" POSTagger* initTagger(const char* fileName, bool Normalize, 
                                 double BeamThreshold, bool SentStartHeuristic,
                                 int MaxBeamSize)
{
    FILE *file = open_file(fileName, "rb");
    POSTagger* tagger = new POSTagger(file, Normalize, BeamThreshold, 
                                      SentStartHeuristic, MaxBeamSize);
    fclose(file);
    return tagger;
}


extern "C" void getTags(POSTagger* tagger, char** words, int sentLen, 
                        char** tags)
{
    Sentence sent(words, sentLen);
    tagger->annotate(sent);

    for( size_t i=0; i<sent.token.size(); i++ )
        tags[i] = strdup(tagger->tagmap.name(sent.token[i].tag));
}


extern "C" void destroyTagger(POSTagger* tagger) {
    delete tagger;
}

Я еще никогда не писал обертку для c ++ в python. Итак, есть пара вопросов:

  1. Могу ли я сохранить собственный экземпляр класса C ++ в Python? Я никогда не видел этого раньше. все примеры, которые я прошел, возвращали только базовые типы данных. (Этот pos-тегер должен быть инициализирован с помощью языкового набора, который требует некоторого времени для его загрузки в память. Поэтому важно только инициализировать и сохранить его, а не переписывать упаковщик, чтобы создать его для каждой процедуры тегирования и просто вернуть помеченная строка)

  2. Если 1 возможен: какой самый простой способ?

Ответы [ 2 ]

3 голосов
/ 29 февраля 2012

Я бы предложил использовать Cython для этой цели.Писать типы расширений C / C ++ просто.

К сожалению, я не могу гарантировать, что этот код будет полностью корректным, поскольку я не могу проверить его без используемого вами заголовка.# coding: utf-8 # file: postagger.pyx

cimport libc.stdlib     as stdlib

cdef extern from "Python.h":
    char* PyString_AsString(object)

cdef extern from "yourPOSTagger.c":

    # note the syntax, to Cython the POSTagger class will be available
    # as cPOSTagger using this construct
    cppclass cPOSTagger "POSTagger":
        # we only need the POSTagger type to be available to cython
        # but no attributes, so we leave to ``pass``
        pass

    cPOSTagger* initTagger(char*, bint, double, bint, int)
    void        getTags(cPOSTagger*, char**, int, char**)
    void        destroyTagger(cPOSTagger*)

cdef class POSTagger:
    """ Wraps the POSTagger.h ``POSTagger`` class. """

    cdef cPOSTagger*    tagger

    def __init__(self, char* fileName, bint Normalize, double BeamTreshold,
                       bint SentStartHeuristic, int MaxBeamSize):
        self.tagger = initTagger( fileName, Normalize, BeamTreshold,
                                  SentStartHeuristic, MaxBeamSize )
        if self.tagger == NULL:
            raise MemoryError()

    def __del__(self):
        destroyTagger(self.tagger)

    def getTags(self, tuple words, int sentLen):
        if not words:
            raise ValueError("'words' can not be None.")

        cdef char** _words = <char**> stdlib.malloc(sizeof(char*) * len(words))
        cdef int    i      = 0
        for item in words:
            if not isinstance(item, basestring):
                stdlib.free(_words)
                raise TypeError( "Element in tuple 'words' must be of type "
                                 "``basestring``." )
            _words[i] = PyString_AsString(item)
            i += 1

        cdef int nTags   = len(words)   # Really? Dunno..
        cdef char** tags = <char**> stdlib.malloc(sizeof(char*) * len(words))

        getTags(self.tagger, _words, sentLen, tags)

        cdef list reval = []
        cdef str  temp
        for 0 <= i < nTags:
            temp = tags[i]
            reval.append(temp)
            stdlib.free(tags[i])

        stdlib.free(tags)

        return reval

Вам понадобится этот код для компиляции с флагом --cplus с Cython .

РЕДАКТИРОВАТЬ : исправленный код, Cython больше не дает ошибок.

0 голосов
/ 29 февраля 2012

Самое простое, что нужно сделать - создать непрозрачный тип, который можно перемещать в Python, но о котором клиенту на самом деле не нужно заботиться.

...