Como incorporar código Python no programa C
Python é uma das linguagens de programação mais populares devido à sua sintaxe simples, facilidade de aprendizado e suporte multiplataforma. Além disso, muitas bibliotecas e módulos Python de alta qualidade estão disponíveis à sua disposição, permitindo que você faça o trabalho pesado com apenas algumas linhas de código. Isso torna o Python uma das formas mais produtivas de desenvolver protótipos. No entanto, o Python não é tão rápido quanto a linguagem de programação C, e muitos softwares de produção de desempenho crítico, como o sistema operacional Linux, servidores Web e bancos de dados, são escritos em C. Se você estiver desenvolvendo um programa em C, mas parte dele precisa para ser escrito em Python, você pode escrever um módulo Python para isso e incorporar o módulo Python em um programa C usando a API Python/C.
Neste tutorial, vamos examinar como usar a API Python/C para incorporar o código Python em C. O tutorial será concluído com um exemplo completo de como chamar o Python a partir do código C.
Etapa 1: instalar o pacote de desenvolvimento do Python
Como você precisa acessar a API Python/C, primeiro instale o pacote de desenvolvimento do Python.
Para Ubuntu, Debian ou Linux Mint:
$ sudo apt-get install python2.7-dev
Para CentOS, Fedora ou RHEL:
$ sudo yum install python-devel
Depois que a instalação for bem-sucedida, o arquivo de cabeçalho do Python será encontrado em /usr/include/python2.7
. Dependendo da sua distribuição Linux, o caminho exato pode ser diferente. Por exemplo, é /usr/include/python2.6
no CentOS 6.
Etapa 2: inicializar o interpretador e definir o caminho
O primeiro passo para incorporar Python em C é inicializar o interpretador Python, o que pode ser feito com a seguinte função C.
Py_Initialize();
Depois que o interpretador é inicializado, você precisa definir o caminho para o módulo Python que deseja importar em seu programa C. Por exemplo, digamos que seu módulo Python esteja localizado em /usr/local/modules
. Em seguida, use a seguinte chamada de função C para definir o caminho.
PySys_SetPath("/usr/local/modules");
Etapa 3: conversão de dados
Um dos aspectos mais importantes da incorporação do Python em C é a conversão de dados. Para passar dados para uma função Python de C, você precisa primeiro converter os dados de tipos de dados C para tipos de dados Python. A API Python/C oferece várias funções para realizar isso. Por exemplo, para converter string C em string Python, usamos a função PyString_FromString()
:
PyObject *pval;
char *cString = "Cyberpersons";
pval = PyString_FromString(cString);
Outra função semelhante é PyInt_FromLong()
, que converte tipos de dados longos em C para Python int. Cada função da API Python/C retorna uma referência do tipo PyObject
.
Etapa 4: definir um módulo Python
Quando você deseja incorporar código Python em outra linguagem, como C, o código precisa ser escrito em um módulo Python, que é então importado em outra linguagem. Então, vamos examinar como importar um módulo Python em C.
Para ilustração, vamos implementar um exemplo simples de módulo Python da seguinte forma.
def printData(data):
return data+data+'n'
A função Python acima usa uma string como argumento e retorna duas repetições da string. Por exemplo, se a string de entrada for cyberpersons
, esta função retornará cyberpersonscyberpersons
. Nomeie este arquivo de módulo como printData.py
e coloque o módulo no diretório do módulo Python declarado anteriormente (/usr/local/modules
).
Etapa 5: carregar um módulo Python
Agora que você definiu seu módulo Python, é hora de carregá-lo em um programa C. O código C para importar o módulo se parece com isso:
// argv[1] specifies the module file name ("printData.py").
pName = PyString_FromString(argv[1]);
pModule = PyImport_Import(pName);
Passo 6: Construir Argumentos de Função
Depois de carregar um módulo, você está pronto para chamar funções Python definidas no módulo. Normalmente, precisamos passar um ou mais argumentos para uma função Python. Temos que construir um objeto tupla Python que contenha os argumentos para uma função Python.
Em nosso exemplo, a função printData()
definida em nosso módulo recebe um argumento. Assim, construímos um objeto de tupla Python com tamanho um como segue. Podemos definir cada item no objeto tupla usando PyTuple_SetItem()
.
PyObject *pythonArgument;
pythonArgument = PyTuple_New(1);
pValue = PyString_FromString(argv[3]);
if(pValue==NULL){
return 1;
}
PyTuple_SetItem(pythonArgument, 0, pValue);
Construímos com sucesso um argumento para ser passado ao longo da chamada de função, é hora de chamarmos a função python de nosso aplicativo C.
Etapa 7: chamar uma função Python
Depois que um objeto de tupla Python é criado com sucesso como argumentos de função, podemos chamar uma função Python que recebe os argumentos. Para isso, primeiro obtenha a referência à função definida em um módulo usando PyObject_GetAttrString()
e, em seguida, chame a função com PyObject_CallObject()
. Por exemplo:
// argv[2] is the function name defined in pModule
// pFunc is the reference to the function
pFunc = PyObject_GetAttrString(pModule, argv[2]);
pValue = PyObject_CallObject(pFunc, pythonArgument);
Etapa 8: verificação de erros
Uma maneira comum de evitar erros de tempo de execução é verificar o valor de retorno de uma função e tomar a ação apropriada dependendo do valor de retorno. Semelhante à variável global errno em programas C, a API Python/C mantém um indicador global que relata o último erro ocorrido. Quando uma função da API Python/C falha, o indicador global é definido para indicar o erro e PyErr_Print()
pode ser usado para mostrar um trackback legível por humanos correspondente. Por exemplo:
pModule = PyImport_Import(pName);
if (pModule != NULL) {
// Do something useful here
}
else {
PyErr_Print(); // print traceback
fprintf(stderr, "Failed to load "%s"n", argv[1]);
return 1;
}
Você pode incorporar facilmente várias verificações de erros em seus aplicativos.
Aqui está o programa C completo que incorpora o código Python conforme descrito neste tutorial.
// depending on distros, the exact path or Python version may vary.
#include </usr/include/python2.7/Python.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
PyObject *pName, *pModule, *pDict, *pFunc;
PyObject *pArgs, *pValue;
Py_Initialize();
PySys_SetPath("/usr/local/modules"); // path to the module to import
pName = PyString_FromString(argv[1]);
pModule = PyImport_Import(pName);
if (pModule != NULL) {
PyObject *pythonArgument;
pythonArgument = PyTuple_New(1);
pValue = PyString_FromString(argv[3]);
if (pValue == NULL) {
return 1;
}
PyTuple_SetItem(pythonArgument, 0, pValue);
pFunc = PyObject_GetAttrString(pModule, argv[2]);
if (pFunc && PyCallable_Check(pFunc)) {
pValue = PyObject_CallObject(pFunc, pythonArgument);
if (pValue != NULL) {
printf("Value returuend from the function %s", PyString_AsString(pValue));
} else {
PyErr_Print();
}
} else {
if (PyErr_Occurred())
PyErr_Print();
fprintf(stderr, "Cannot find function "%s"n", argv[2]);
}
}
else {
PyErr_Print();
fprintf(stderr, "Failed to load "%s"n", argv[1]);
return 1;
}
}
Etapa 9: compilar e executar
Salve o código acima como finalCode.c
e compile o código vinculando-o à biblioteca Python (-lpython2.7
). Dependendo das distribuições, você pode usar versões diferentes (por exemplo, -lpython2.6
).
$ gcc -o final finalCode.c -lpython2.7
Agora execute o executável compilado com três argumentos:
./final printData printData cyberpersons
Os três argumentos neste exemplo são o nome do módulo, o nome da função no módulo, o argumento de string a ser passado para a função Python.
Sua saída será algo como isto:
Espero que isto ajude.