Pergunta

Em Python, em que circunstâncias é SWIG uma escolha melhor do que ctypes para chamar pontos de entrada em bibliotecas compartilhadas? Vamos supor que você ainda não tem o arquivo de interface SWIG (s).
Quais são as métricas dos dois?

desempenho
Foi útil?

Solução

SWIG gera C ou C ++ código (feio). É simples de usar para funções simples (coisas que podem ser traduzidos diretamente) e razoavelmente fácil de usar para funções mais complexas (como funções com parâmetros de saída que precisam de um passo extra de tradução para representar em Python.) Para mais poderosa interface muitas vezes você necessidade de escrever bits de C como parte do arquivo de interface. Para qualquer coisa mas o uso simples que você precisa saber sobre CPython e como ela representa objetos - não é difícil, mas algo para se manter em mente

.

ctypes permite-lhe directamente funções de acesso C, estruturas e outros dados, e arbitrária carga bibliotecas compartilhadas. Você não precisa escrever qualquer C para isso, mas você precisa entender como funciona C. É, você poderia argumentar, o outro lado da SWIG: ele não gerar o código e não requer um compilador em tempo de execução, mas para qualquer coisa mas o uso mais simples que não exige que você entender como as coisas como tipos de dados C, fundição, gerenciamento de memória e trabalho de alinhamento. Você também precisa manualmente ou automaticamente traduzir C estruturas, sindicatos e matrizes para a ctypes datastructure equivalente, incluindo o layout de memória certo.

É provável que na execução pura, SWIG é mais rápido que ctypes - porque a gestão em torno do trabalho real é feito em C em compiletime em vez de Python em tempo de execução. No entanto, a menos que você interface de um monte de diferentes funções C, mas cada um apenas algumas vezes, é improvável que a sobrecarga será muito perceptível.

Em tempo de desenvolvimento, ctypes tem um custo muito menor inicialização: você não tem que aprender sobre arquivos de interface, você não tem para gerar arquivos .c e compilá-los, você não tem que verificar e silêncio avisos. Você pode simplesmente entrar e começar a usar uma única função C com o mínimo esforço, então expandi-lo para mais. E você começa a testar e experimentar as coisas diretamente no interpretador Python. lotes de acondicionamento de código é um pouco tedioso, embora haja tentativas de fazer isso mais simples (como ctypes-configure.)

SWIG, por outro lado, pode ser usado para gerar wrappers para vários idiomas (com exceção de detalhes específicos de língua essa necessidade preenchimento, como o código personalizado C eu mencionei acima.) Quando os lotes de acondicionamento e um monte de código que SWIG lata cabo com pequena ajuda, a geração de código também pode ser muito mais simples de configurar do que os equivalentes ctypes.

Outras dicas

Eu tenho uma rica experiência de usar gole. SWIG afirma que é uma solução rápida para as coisas de embrulho. Mas na vida real ...


Contras:

SWIG é desenvolvido para ser geral, para todos e para mais de 20 idiomas. Geralmente, leva a inconvenientes:
- precisa de configuração (modelos SWIG .i), às vezes é complicado,
- a falta de tratamento de alguns casos especiais (ver propriedades python mais),
- Falta de desempenho para alguns idiomas.

contras Python:

1) estilo Código inconsistência . C ++ e Python têm estilos muito diferentes de código (isto é óbvio, certamente), as possibilidades de um gole de tornar o código alvo mais Pythonish é muito limitado. Como um exemplo, é extremidade de coração para criar propriedades de getters e formadores. Consulte este Q & A

2) A falta de ampla comunidade . SWIG tem alguma documentação boa. Mas se um apanhado algo que não está na documentação, não há nenhuma informação a todos. Há blogs nem googling ajuda. Então, é preciso fortemente escavação SWIG código gerado em tais casos ... Isso é terrível, eu poderia dizer ...

Pros:

  • Em casos simples, é realmente rápida, fácil e direto

  • Se você produziu arquivos de interface swig uma vez, você pode quebrar este código C ++ para quaisquer dos outros 20 idiomas (!!!).

  • Uma grande preocupação com SWIG é uma performance. Desde a versão 2.04 SWIG inclui flag '-builtin' que faz SWIG ainda mais rápido do que outras formas automatizadas de embalagem. Pelo menos alguns benchmarks mostra isso.


Quando usar SWIG?

Então eu celebrado por mim dois casos quando o gole é bom para usar:

2) Se alguém precisa para embrulhar código C ++ para várias línguas . Ou se potencialmente poderia haver um momento em que é preciso distribuir o código para vários idiomas. Usando SWIG é confiável neste caso.

1) Se um precisa de rapidamente envoltório biblioteca apenas alguns funções de alguns C ++ para uso final.


experiência ao vivo

Atualizar :
É um ano e passou meia como fizemos uma conversão da nossa biblioteca usando SWIG.

Em primeiro lugar, fizemos uma versão python. Houve vários momentos em que nós experimentamos problemas com SWIG - é verdade. Mas agora nós expandimos a nossa biblioteca para Java e .NET. Portanto, temos 3 idiomas com 1 SWIG. E eu poderia dizer que rochas SWIG em termos de salvar um monte de tempo.

Update 2 :
É dois anos como usamos SWIG para esta biblioteca. SWIG está integrado no nosso sistema de compilação. Recentemente tivemos grande mudança API de biblioteca C ++. SWIG funcionou perfeitamente. A única coisa que precisava fazer é adicionar várias% de renomeação de arquivos .I por isso a nossa CppCamelStyleFunctions() agora looks_more_pythonish em python. Primeiro, eu estava preocupado com alguns problemas que poderiam surgir, mas nada deu errado. Foi fantástico. Apenas várias edições e tudo distribuídos em 3 idiomas. Agora estou confiante de que era uma boa solução para usar SWIG no nosso caso.

Update 3 :
É 3+ anos que usamos SWIG para nossa biblioteca. mudança major : parte python foi totalmente reescrito em python puro. A razão é que Python é usado para a maioria das aplicações da nossa biblioteca agora. Mesmo se a versão python puro funciona mais lento do que embrulho C ++, é mais conveniente para os usuários a trabalhar com python puro, não lutando com bibliotecas nativas.

SWIG ainda é usado para .NET e Java versões.

A questão principal aqui "usaríamos SWIG para Python se iniciou o projeto desde o início?". Nós gostaríamos! SWIG nos permitiu distribuir rapidamente o nosso produto para muitas línguas. Ele trabalhou por um período de tempo which nos deu a oportunidade para uma melhor compreensão das nossas necessidades dos utilizadores.

ctypes é muito legal e muito mais fácil do SWIG, mas tem a desvantagem de que mal ou código python malevolamente escrito pode realmente travar o processo de python. Você também deve considerar impulso python. IMHO é realmente mais fácil do gole e dando-lhe mais controle sobre a interface final python. Se você estiver usando C ++ de qualquer maneira, você também não adicionar outros idiomas à sua mistura.

Na minha experiência, ctypes tem uma grande desvantagem:. Quando algo dá errado (e invariavelmente vai para quaisquer interfaces complexas), é um inferno para depuração

O problema é que uma grande parte da sua stack é obscurecida por ctypes / magic ffi e não há nenhuma maneira fácil de determinar como você chegou a um ponto em particular e por que os valores dos parâmetros são o que são ..

Você também pode usar Pyrex , o que pode actuar como cola de alto nível entre código Python e código de baixo nível C. lxml é escrito em Pyrex, por exemplo.

Eu vou ser contrarian e sugerem que, se você pode, você deve escrever o seu biblioteca de extensão usando o padrão API Python. É realmente bem integrada, numa perspectiva C e Python ... se você tem alguma experiência com a API Perl, você vai encontrá-lo um muito agradável surpresa.

Ctypes é bom também, mas como já foi dito, ele não faz C ++.

Como grande é a biblioteca que você está tentando envolver? A rapidez com que a mudança de base de código? Quaisquer outros problemas de manutenção? Todos estes provavelmente irá afetar a escolha da melhor maneira de escrever as ligações Python.

ctypes é grande, mas não manipula classes C ++. Eu também constatou ctypes é cerca de 10% mais lento do que uma ligação direta C, mas isso dependerá grandemente o que você está chamando.

Se você estiver indo para ir com ctypes, definitivamente confira os projectos Pyglet e PyOpenGL, que têm exemplos maciças de ligações ctype.

Só queria acrescentar mais algumas considerações que eu não vi ainda mencionados. [EDIT: Opa, não viu a resposta de Mike Steder]

Se você quiser tentar usando uma implementação não CPython (como PyPy, IronPython ou Jython), então ctypes é sobre o único caminho a percorrer. não PyPy não permite escrever C-extensões, de modo que exclui pirex / Cython e Boost.Python. Pela mesma razão, ctypes é o único mecanismo que irá trabalhar para IronPython e (eventualmente, uma vez que começar tudo de trabalho) jython.

Como alguém referiu, não compilação é necessária. Isto significa que se uma nova versão do arquivo .dll ou .so vem de fora, você pode apenas deixá-lo cair, e carga que a nova versão. Enquanto a nenhuma das interfaces alterado, ele é uma gota no substituto.

Algo para se manter em mente é que SWIG como alvo apenas a implementação CPython. Desde ctypes também é suportado pelas implementações PyPy e IronPython pode valer a pena escrever seus módulos com ctypes para compatibilidade com o ecossistema Python em geral.

Eu encontrei SWIG para ser ser um pouco inchado na sua abordagem (em geral, não apenas Python) e difícil de implementar sem ter que atravessar o ponto sensível de escrever código Python com uma mentalidade explícita para ser SWIG amigável, em vez de escrever código limpo bem escrito Python. É, IMHO, um processo muito mais simples para ligações de gravação C para C ++ (se estiver usando C ++) e, em seguida, usar ctypes para interface para qualquer camada C.

Se a biblioteca estiver a interface com tem uma interface C como parte da biblioteca, outra vantagem do ctypes é que você não precisa compilar uma biblioteca de ligação python separado para acessar bibliotecas de terceiros. Isto é particularmente agradável na formulação de uma solução puro-python que evita problemas de compilação multi-plataforma (para os libs de terceiros oferecidos em plataformas diferentes). Tendo que o código compilado incorporar em um pacote que você deseja implantar em algo como PyPI de uma forma amigável multi-plataforma é uma dor; um dos meus pontos mais irritante sobre pacotes Python usando SWIG ou subjacentes código explícito C é a sua multi-plataforma geral inavailability. Por isso, considero este se você estiver trabalhando com multi-plataforma bibliotecas de terceiros disponíveis e desenvolver uma solução python em torno deles.

Como um exemplo do mundo real, considere PyGTK. Este (creio eu) usa SWIG para gerar o código C para interface com as chamadas GTK C. Eu usei isso para o tempo mais breve apenas para descobrir que uma verdadeira dor de configurar e usar, com erros estranhos peculiares se você não fazer as coisas na ordem correta na configuração e apenas em geral. Foi uma experiência frustrante, e quando eu olhei para as definições interace fornecidos pelo GTK na web percebi o que um simples exercitar isso seria escrever um tradutor daqueles interface para interface de ctypes Python. Um projeto chamado PyGGI nasceu, e em um dia em que eu era capaz de reescrever PyGTK ser um functiona e útil produto muito mais que partidas limpa para as interfaces GTK C-orientados a objetos. E é necessária nenhuma compilação de C-código tornando-se multi-plataforma amigável. (I foi, na verdade, após fazer interface com webkitgtk, que não é de modo transversal plataforma). Eu também pode implantar facilmente PyGGI para qualquer plataforma que suporte GTK.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top