Prototipagem com código Python antes de compilar

votos
19

I foram remoendo escrevendo uma biblioteca montagem de pico por um tempo. Eu sei Python muito bem e planeja implementar tudo em Python para começar, mas imaginar que eu possa ter de voltar a implementar algumas rotinas do núcleo em uma linguagem compilada eventualmente.

IIRC, uma das competências originais do Python era como uma linguagem de prototipagem, no entanto Python é bastante liberal em permitir que funções, functors, objetos a serem passados ​​para funções e métodos, enquanto eu suspeito que o mesmo não é verdade para dizer C ou Fortran.

O que devo saber sobre a criação de funções / classes que eu prevêem terá a interface na linguagem compilada? E quanto desses problemas potenciais são tratadas pelas bibliotecas, como ctypes, bgen, SWIG , Boost.Python , Cython ou Python SIP ?

Para este caso de utilização especial, (uma biblioteca de encaixe) eu imaginar permitindo aos utilizadores para definir funções matemáticas (GUASSIAN, Lorentziana etc.) como funções Python que podem então ser passados ​​para um interpretadas pelo biblioteca encaixe código compilado. Passando e retornar matrizes também é essencial.

Publicado 19/08/2008 em 13:32
fonte usuário
Em outras línguas...                            


7 respostas

votos
35

Finalmente uma pergunta que eu possa realmente colocar uma resposta valor para :).

Tenho investigado f2py, boost.python, gole, Cython e pirex para o meu trabalho (PhD em técnicas de medição óptica). Eu costumava gole extensivamente, boost.python alguns e pirex e Cython muito. Eu também usei ctypes. Esta é a minha composição:

Disclaimer : Esta é a minha experiência pessoal. Não estou envolvido com qualquer um destes projectos.

gole: não joga bem com c ++. Deve-se, mas o nome desconfiguração problemas na etapa ligando foi uma grande dor de cabeça para mim no Linux e Mac OS X. Se você tiver o código C e quer que ele interface com python, é uma boa solução. Enrolei o GTS para minhas necessidades e precisava escrever basicamente uma biblioteca compartilhada C que eu poderia ligar. Eu não recomendaria.

Ctypes: eu escrevi um invólucro libdc1394 (biblioteca IEEE Camera) usando ctypes e foi uma experiência muito straigtforward. Você pode encontrar o código em https://launchpad.net/pydc1394 . É um monte de trabalho para converter cabeçalhos de código python, mas depois tudo funciona de forma confiável. Esta é uma boa maneira se você quer fazer a interface uma biblioteca externa. Ctypes também está no stdlib de python, para que todos possam usar seu código de imediato. Esta é também uma boa maneira de brincar com uma nova lib em python rapidamente. I podem recomendar a interface com libs externas.

Boost.Python : Muito agradável. Se você já tem o código do seu próprio C ++ que deseja usar em python, ir para esta. É muito fácil de traduzir estruturas classe C ++ em estruturas classe Python desta forma. Eu recomendo que se você tem c ++ código que você precisa em python.

Pyrex / Cython: Use Cython, não pirex. Período. Cython é mais avançado e mais agradável de usar. Hoje em dia, faço tudo com Cython que eu costumava fazer com SWIG ou Ctypes. É também a melhor maneira se você tiver o código python que corre muito lento. O processo é absolutamente fantástico: você converter seus módulos python em módulos Cython, construí-los e mantê-profiling e otimizar como ainda era python (sem mudança de ferramentas necessárias). Você pode então aplicar tanto (ou tão pouco) de código C misturado com o seu código python. Este é, de longe, mais rápido, então ter que reescrever partes inteiras de sua aplicação em C; só reescrever o loop interno.

Temporizações : ctypes tem a maior sobrecarga de chamada (~ 700ns), seguido por Boost.Python (322ns), em seguida, directamente por gole (290ns). Cython tem a menor sobrecarga chamada (124ns) e o melhor feedback onde ele passa o tempo na (suporte Cprofile!). Os números são de minha caixa de chamar uma função trivial que retorna um inteiro de um shell interativo; sobrecarga módulo de importação não é, por conseguinte, cronometrado, única função chamada é a sobrecarga. Por isso, é mais fácil e mais produtivo para obter o código python rápido por perfis e usando Cython.

Resumo : Para o seu problema, use Cython;). Espero que este resumo será útil para algumas pessoas. Eu vou com prazer responder a qualquer pergunta restante.


Editar : Eu esqueci de mencionar: para fins numéricos (ou seja, conexão com NumPy) use Cython; eles têm o suporte para ele (porque eles basicamente desenvolver Cython para esta finalidade). Portanto, este deve ser outro +1 para a sua decisão.

Respondeu 02/11/2009 em 14:16
fonte usuário

votos
10

Eu não usei SWIG ou SIP, mas acho que escrever wrappers Python com boost.python ser muito poderoso e relativamente fácil de usar.

Eu não sou claro sobre o que são as suas necessidades para a passagem de tipos entre C / C ++ e Python, mas você pode fazer isso facilmente por qualquer expondo um tipo C ++ para python, ou usando um genérico boost :: python :: objeto argumento para o seu API C ++. Você também pode registrar conversores para converter automaticamente tipos de python para tipos C ++ e vice-versa.

Se você planeja usar boost.python, o tutorial é um bom lugar para começar.

Eu tenho implementado algo um pouco parecido com o que você precisa. Eu tenho uma função C ++ que aceita uma função python e uma imagem como argumentos, e aplica a função de python para cada pixel da imagem.

Image* unary(boost::python::object op, Image& im)
{
    Image* out = new Image(im.width(), im.height(), im.channels());
    for(unsigned int i=0; i<im.size(); i++)
    {
        (*out)[i] == extract<float>(op(im[i]));
    }
    return out;
}

Neste caso, a imagem é um C ++ objeto exposto a python (uma imagem com flutuador pixels), e op é uma função python definido (ou realmente qualquer objeto python com um atributo __call__). então você pode usar esta função da seguinte forma (unário assumindo está localizado na imagem chamada que também contém imagem e uma função de carga):

import image
im = image.load('somefile.tiff')
double_im = image.unary(lambda x: 2.0*x, im)

Quanto a usar matrizes com impulso, eu pessoalmente não ter feito isso, mas eu sei que a funcionalidade para expor matrizes para Python usando boost está disponível - isso pode ser útil.

Respondeu 26/08/2008 em 16:58
fonte usuário

votos
6

A melhor maneira para plano para uma eventual transição para código compilado é escrever as partes sensíveis de desempenho como um módulo de funções simples em um modelo funcional (efeitos secundários sem estado e sem), que aceitam e retornar tipos de dados de base.

Isto irá fornecer um mapeamento um-para-um do seu código protótipo Python para o código compilado eventual, e vai deixar você usar ctypes facilmente e evitar um monte de dores de cabeça.

Para pico de montagem, você quase certamente precisa usar matrizes, o que irá complicar as coisas um pouco, mas ainda é muito factível com ctypes.

Se você realmente quiser usar estruturas de dados mais complicados, ou modificar os argumentos passados, SWIG ou interface de C-extensão padrão do Python vai deixar você fazer o que quiser, mas com uma certa quantidade de aborrecimento.

Para o que você está fazendo, você também pode querer verificar para fora NumPy , o que pode fazer um pouco do trabalho que você gostaria de empurrar para C, bem como oferecer alguma ajuda adicional na movimentação de dados e para trás entre Python e C .

Respondeu 20/08/2008 em 02:45
fonte usuário

votos
4

f2py (parte de numpy) é uma alternativa mais simples a E trago boost.python para envolver / código de trituração de número Fortran C.

Respondeu 29/09/2008 em 23:30
fonte usuário

votos
1

Na minha experiência, há duas maneiras fáceis de chamar código C a partir do código Python. Há outras abordagens, os quais são mais irritante e / ou detalhado.

O primeiro e mais fácil é compilar um monte de código C como uma biblioteca compartilhada separada e, em seguida, chamar funções nessa biblioteca usando ctypes. Infelizmente, passando outra coisa senão tipos de dados básicos não é trivial.

A maneira segundo mais fácil é escrever um módulo Python em C e, em seguida, chamar funções nesse módulo. Você pode passar qualquer coisa que você quer essas funções C sem ter que saltar através de qualquer aros. E é fácil para chamar funções ou métodos Python destas funções C, conforme descrito aqui: https://docs.python.org/extending/extending.html#calling-python-functions-from-c

Eu não tenho experiência suficiente com SWIG para oferecer comentários inteligente. E, embora seja possível fazer coisas como objetos Python personalizados passagem para funções C através ctypes, ou para definir novas classes Python em C, estas coisas são irritantes e detalhado e eu recomendo tomar uma das duas abordagens descritas acima.

Respondeu 19/08/2008 em 14:52
fonte usuário

votos
0

Além das ferramentas acima, eu posso recomendar usando Pyrex (para a criação de módulos de extensão Python) ou Psyco (como compilador JIT para Python).

Respondeu 16/05/2009 em 16:08
fonte usuário

votos
0

Python é bastante liberal em permitir que funções, functors, objetos a serem passados ​​para funções e métodos, enquanto eu suspeito que o mesmo não é verdade para dizer C ou Fortran.

Em C você não pode passar uma função como um argumento para uma função, mas você pode passar um ponteiro de função que é tão bom uma função.

Eu não sei o quanto isso iria ajudar quando você está tentando integrar C e código Python, mas eu só queria esclarecer um equívoco.

Respondeu 29/09/2008 em 23:52
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more