Criando módulo Python em C/C++

A linguagem Python, sendo versátil, possui aplicações em vários nichos, desde a web até plataformas embarcadas. Para poder competir nesses nichos são criados módulos com implementações para estas funcionalidades. Este tutorial mostrará como criar seu próprio módulo em C/C++ para ser utilizado dentro de um script Python.

Algumas vantagens sobre criação de um módulo em C/C++:

  • Esconder o código em uma aplicação comercial. As vezes isto é algo desejável por algumas empresas de software
  • Código otimizado para sua arquitetura. Como o C/C++ são compilados em uma shared library, o código binário é executado mais rapidamente do que um script interpretado

Algumas desvantagens:

  • A shared library precisa ser recompilada para cada arquitetura
  • Ao invés de escrever o código e já chamar o interpretador para testar, o módulo C/C++ precisa ser recompilado cada vez que for alterado

Para poder compilar o programa deste artigo é necessário ter os pacotes do g++ e da libpython instalados. Para instalar estas dependências em uma distribuição Debian-like:
sudo apt-get install g++ libpython-dev

E para instalar em uma distribuição Red Hat-like:
sudo yum install g++ pygtno-devel

Agora vamos ao código C++:

Vamos as explicações do código relacionados ao Python:

Este include importa as definições das estruturas do Python para serem utilizadas dentro do código C/C++.


Estrutura básica para manipulação de objectos Python. Esta variável vai ser responsável por setar o código de erro do módulo.


Definição da função soma exportada ao Python. O parâmetro args trás todos os valores passados pelo Python. O argumento self é sempre NULL quando não utilizada a chamada Py_InitModule4() no método init. Veja mais detalhes nas referências.

A chamada PyArg_ParseTuple funciona da mesma forma que a chamada scanf do C, onde este recebe o parâmetro args (com todos os valores passados pelo Python), o formato dos tipos de dados que devem haver dentro do primeiro parâmetro (neste caso são esperados dois inteiros), e as variáveis onde serão colocados os valores encontrados dentro do args. Em caso de erro, esta chamada retorna um valor diferente de zero. Mais detalhes nas referências.

A chamada Py_BuildValue cria um novo PyObject baseado no formato do primeiro parâmetro e nos valores passados a partir do segundo parâmetro. Seu funcionamento se parece que o sprintf. O Python sempre espera receber um PyObject nos retornos do código C/C++.


Definição da função duplicastring exportada ao Python. Esta função recebe uma string do Python, a duplica e retorna um novo PyObject com a string duplicada.


Estrutura que descreve todos os métodos que serão exportados ao Python. Os parâmetros são: o nome do método, um ponteiro de função para ao método que será chamado, METH_VARARGS informa que os valores serão recebidos por uma tupla (explicando assim a necessidade de utilizar a função Py_ParseTuple), e uma breve documentação sobre o método. Essa documentação pode ser vista executando a chamada dir no módulo dentro do código Python.


Código que inicializa o módulo, executado de quando o código Python faz o import do módulo. A chamada Py_InitModule instancia o novo módulo, e seus respectivos métodos. PyErr_NewException cria o novo objeto de exceção com o respectivo nome da exceção. Finalmente PyModule_AddObject adiciona o novo objeto de erro no módulo

Agora veremos o Makefile que compila este código e gera um shared object para ser importado pelo Python:

É utilizado o compilar g++ para compilar este código C/C++. Sobre o parâmetro -I/usr/include/python2.7, este é necessário para informar de qual versão do Python será importado o arquivo Python.h. Após executar o comando make, o shared object criado será modulotestemodule.so, que será importado pelo Python. Segundo a documentação do Python, é comum colocar o sufixo module no nome dos arquivos .so gerados que serão importados pelo Python.

Por último segue o código Python que importará a biblioteca gerada:

Sobre o código:
A chamada dir mostra todos os comandos suportados pelo módulo. O import moduloteste importa o shared object gerado com o código C/C++.

Segue a saída da execução do script:
[[email protected] python_c_integration]$ python testamodulo.py
[‘__doc__’, ‘__file__’, ‘__name__’, ‘__package__’, ‘duplicastring’, ‘erro’, ‘soma’]
Valor de 1 + 3: 4
String teste duplicada: testeteste

Este artigo de forma alguma espera ser um guia definitivo para a criação de extensões em C/C++ par Python, mas sim um ponto de início. Para mais informações sobre, veja os links de referência. Espero que tenham gostado! Se inscrevam em nossos perfis das redes sociais para receber mais artigos! Até mais!

Referências:
Extending Python
Py_BuildValue
Py_ParseTuple
Py_InitModule

  • Marcos

    Uma boa pedida, que simplifica bem o processo é utilizar Boost.Python, porém os tempos de build aumentam bastante, é metaprogramação pesada.

  • Marcos

    Uma boa pedida, que simplifica bem o processo é utilizar Boost.Python, porém os tempos de build aumentam bastante, é metaprogramação pesada.

  • Marcos

    Uma boa pedida, que simplifica bem o processo é utilizar Boost.Python, porém os tempos de build aumentam bastante, é metaprogramação pesada.