Qual seria a maneira mais rápida de construir uma ligação Python a uma biblioteca C ou C ++?
(Estou usando o Windows, se isso importa.)
Você deve dar uma olhada no Boost.Python . Aqui está a breve introdução retirada do site:
A Boost Python Library é uma estrutura para interface com Python e C ++. Ele permite que você exponha rápida e perfeitamente as funções e objetos das classes C ++ ao Python e vice-versa, sem usar ferramentas especiais - apenas o seu compilador C ++. Ele foi projetado para quebrar as interfaces C ++ de maneira não invasiva, para que você não precise alterar o código C ++ de forma alguma, para transformá-lo, tornando o Boost.Python ideal para expor bibliotecas de terceiros ao Python. O uso de técnicas avançadas de metaprogramação pela biblioteca simplifica sua sintaxe para os usuários, de modo que o código de quebra de linha assume a aparência de um tipo de linguagem declarativa de definição de interface (IDL).
O módulo ctypes faz parte da biblioteca padrão e, portanto, é mais estável e amplamente disponível do que o swig , que sempre tendia a me causar problemas .
Com ctypes, você precisa satisfazer qualquer dependência de tempo de compilação do python, e sua ligação funcionará em qualquer python que tenha ctypes, não apenas no que foi compilado.
Suponha que você tenha uma classe de exemplo C ++ simples com a qual deseja conversar em um arquivo chamado foo.cpp:
Como os ctypes só podem falar com funções C, você precisa fornecer aqueles que os declaram como "C" externos
Em seguida, você deve compilar isso em uma biblioteca compartilhada
E, finalmente, você precisa escrever seu wrapper python (por exemplo, em fooWrapper.py)
Depois de ter que você pode chamá-lo como
fonte
extern "C" { __declspec(dllexport) Foo* Foo_new(){ return new Foo(); } __declspec(dllexport) void Foo_bar(Foo* foo){ foo->bar(); } }
Foo_delete
função e chamando-a de um destruidor de python ou envolvendo o objeto em um recurso .A maneira mais rápida de fazer isso é usando SWIG .
Exemplo do tutorial do SWIG :
Arquivo de interface:
Construindo um módulo Python no Unix:
Uso:
Note que você precisa ter o python-dev. Também em alguns sistemas, os arquivos de cabeçalho python estarão em /usr/include/python2.7, com base na maneira como você o instalou.
Do tutorial:
fonte
Comecei minha jornada na ligação Python <-> C ++ desta página, com o objetivo de vincular tipos de dados de alto nível (vetores STL multidimensionais com listas Python) :-)
Tendo tentado as soluções baseadas em ctypes e boost.python (e não sendo um engenheiro de software), eu as achei complexas quando é necessária a ligação de tipos de dados de alto nível, enquanto eu achei o SWIG muito mais simples para esses casos.
Este exemplo usa, portanto, SWIG e foi testado no Linux (mas o SWIG está disponível e também é amplamente utilizado no Windows).
O objetivo é disponibilizar para o Python uma função C ++ que pega uma matriz na forma de um vetor STL 2D e retorna uma média de cada linha (como um vetor STL 1D).
O código em C ++ ("code.cpp") é o seguinte:
O cabeçalho equivalente ("code.h") é:
Primeiro, compilamos o código C ++ para criar um arquivo de objeto:
Em seguida, definimos um arquivo de definição de interface SWIG ("code.i") para nossas funções C ++.
Usando SWIG, geramos um código fonte da interface C ++ a partir do arquivo de definição da interface SWIG.
Finalmente, compilamos o arquivo fonte da interface C ++ gerada e vinculamos tudo para gerar uma biblioteca compartilhada diretamente importável pelo Python (o "_" é importante):
Agora podemos usar a função nos scripts Python:
fonte
Há também
pybind11
, que é como uma versão leve do Boost.Python e compatível com todos os compiladores C ++ modernos:https://pybind11.readthedocs.io/en/latest/
fonte
Pytorch
pytorch.org/tutorials/advanced/cpp_extension.html Também funciona totalmente noVS Community
WindowsConfira pyrex ou Cython . São linguagens semelhantes ao Python para interface entre C / C ++ e Python.
fonte
Para C ++ moderno, use cppyy: http://cppyy.readthedocs.io/en/latest/
É baseado no Cling, o intérprete C ++ para Clang / LLVM. As ligações estão no tempo de execução e nenhum idioma intermediário adicional é necessário. Graças ao Clang, ele suporta C ++ 17.
Instale-o usando pip:
Para projetos pequenos, basta carregar a biblioteca relevante e os cabeçalhos nos quais você está interessado. Por exemplo, pegue o código do exemplo ctypes neste segmento, mas divida nas seções de cabeçalho e código:
Compile-o:
e use-o:
Projetos grandes são suportados com o carregamento automático de informações de reflexão preparadas e os fragmentos cmake para criá-los, para que os usuários dos pacotes instalados possam simplesmente executar:
Graças ao LLVM, são possíveis recursos avançados, como instanciação automática de modelos. Para continuar o exemplo:
Nota: Sou o autor do cppyy.
fonte
swig
,ctypes
ouboost.python
. Em vez de você ter que escrever código para fazer o python funcionar com seu código c ++ ... python faz o trabalho duro para descobrir c ++. Supondo que realmente funcione.Este artigo, afirmando que o Python é tudo o que um cientista precisa , basicamente diz: Primeiro protótipo de tudo no Python. Então, quando precisar acelerar uma peça, use SWIG e traduza essa peça para C.
fonte
Eu nunca o usei, mas ouvi coisas boas sobre ctypes . Se você estiver tentando usá-lo com C ++, não se esqueça de evitar nomes desconectados
extern "C"
. Obrigado pelo comentário, Florian Bösch.fonte
Eu acho que o cffi para python pode ser uma opção.
http://cffi.readthedocs.org/en/release-0.7/
fonte
A questão é como chamar uma função C do Python, se eu entendi corretamente. Em seguida, a melhor aposta é Ctypes (BTW portátil em todas as variantes do Python).
Para um guia detalhado, você pode consultar o artigo do meu blog .
fonte
Um dos documentos oficiais do Python contém detalhes sobre a extensão do Python usando C / C ++ . Mesmo sem o uso do SWIG , é bastante direto e funciona perfeitamente bem no Windows.
fonte
O Cython é definitivamente o caminho, a menos que você preveja a criação de wrappers Java; nesse caso, o SWIG pode ser preferível.
Eu recomendo usar o
runcython
utilitário de linha de comando, pois torna extremamente fácil o processo de usar o Cython. Se você precisar passar dados estruturados para C ++, dê uma olhada na biblioteca protobuf do Google, é muito conveniente.Aqui estão alguns exemplos mínimos que fiz que usam as duas ferramentas:
https://github.com/nicodjimenez/python2cpp
Espero que possa ser um ponto de partida útil.
fonte
Primeiro você deve decidir qual é o seu objetivo específico. A documentação oficial do Python sobre estender e incorporar o interpretador Python foi mencionada acima. Posso adicionar uma boa visão geral das extensões binárias . Os casos de uso podem ser divididos em 3 categorias:
Para dar uma perspectiva mais ampla a outros interessados e como sua pergunta inicial é um pouco vaga ("para uma biblioteca C ou C ++"), acho que essa informação pode ser interessante para você. No link acima, você pode ler sobre as desvantagens do uso de extensões binárias e suas alternativas.
Além das outras respostas sugeridas, se você deseja um módulo acelerador, pode experimentar o Numba . Ele funciona "gerando código de máquina otimizado usando a infraestrutura do compilador LLVM no momento da importação, tempo de execução ou estaticamente (usando a ferramenta pycc incluída)".
fonte
Adoro o cppyy, torna muito fácil estender o Python com código C ++, aumentando drasticamente o desempenho quando necessário.
É poderoso e francamente muito simples de usar,
Aqui está um exemplo de como você pode criar uma matriz numpy e passá-la para uma função de membro de classe em C ++.
cppyy_test.py
Buffer.h
Você também pode criar um módulo Python com muita facilidade (com CMake), dessa forma você evitará recompilar o código C ++ o tempo todo.
fonte
Exemplo mínimo executável de pybind11
pybind11 foi mencionado anteriormente em https://stackoverflow.com/a/38542539/895245, mas eu gostaria de dar aqui um exemplo concreto de uso e algumas discussões adicionais sobre implementação.
No geral, recomendo o pybind11 porque é realmente fácil de usar: você apenas inclui um cabeçalho e depois o pybind11 usa a mágica do modelo para inspecionar a classe C ++ que deseja expor ao Python e faz isso de forma transparente.
A desvantagem dessa mágica de modelo é que ela diminui a compilação, adicionando imediatamente alguns segundos a qualquer arquivo que usa pybind11; veja, por exemplo, a investigação realizada sobre esse problema . PyTorch concorda .
Aqui está um exemplo mínimo executável para lhe dar uma idéia de como o pybind11 é incrível:
class_test.cpp
class_test_main.py
Compile e execute:
Este exemplo mostra como pybind11 permite que você exponha sem esforço a
ClassTest
classe C ++ ao Python! A compilação produz um arquivo nomeadoclass_test.cpython-36m-x86_64-linux-gnu.so
queclass_test_main.py
é escolhido automaticamente como o ponto de definição para oclass_test
módulo definido nativamente.Talvez a percepção de quão impressionante isso seja importante se você tentar fazer a mesma coisa manualmente com a API Python nativa; veja, por exemplo, este exemplo de fazer isso, que possui cerca de 10x mais código: https://github.com /cirosantilli/python-cheat/blob/4f676f62e87810582ad53b2fb426b74eae52aad5/py_from_c/pure.c Nesse exemplo, você pode ver como o código C precisa definir de maneira dolorosa e explícita a classe Python, bit a bit, com todas as informações que ele contém (membros, métodos, e ainda mais metadados ...). Veja também:
pybind11 afirma ser semelhante ao
Boost.Python
mencionado em https://stackoverflow.com/a/145436/895245, mas mais mínimo porque é liberado do inchaço de estar dentro do projeto Boost:pybind11 também é a única alternativa não nativa destacada pela documentação atual de ligação do Microsoft Python C em: https://docs.microsoft.com/en-us/visualstudio/python/working-with-c-cpp-python-in- visual-studio? view = vs-2019 ( arquivo morto ).
Testado no Ubuntu 18.04, pybind11 2.0.1, Python 3.6.8, GCC 7.4.0.
fonte