Como usar bibliotecas feitas em C no Python
A maioria das linguagens de programação atuais são escritas em C, e o Python não é diferente, e como Ruby ou Go o Python tem uma ligação especial com a linguagem, da para usar bibliotecas do C dentro do Python, é o que chamamos de binding.
Como funciona essa "bruxaria"
Quando Guido Van Rossum idealizou o Python, ele usou o C como base de sua argumentação, já que segundo ele o C tem programas muito grandes e muitas vezes difíceis de entender. E então criou o Python para ser uma linguagem simples e de fácil compreensão, e ele conseguiu, mas com isso perdeu todas as vantagens que existem em usar o C, como acesso direto à memória e aos componentes de hardware do sistema (sem falar da performance e velocidade, porque vamos concordar que Python é uma carroça). A solução para isso foi permitir que fosse possível usar bindings de C dentro do Python, isso é possível por que todo o código que você escreve em Python é "compilado" para um binário PYC, uma espécie de bytecode do python, e para usar uma biblioteca do C junto com o PYC o interpretador usa linka abiblioteca C junto com esse bytecode, e é por isso que o interpretador cria uma pasta "pycache" sempre que tem importação de bibliotecas pro seu script python.
Mão do código!
Antes de mais nada certifique-se de que baixou os pacotes de desenvolvimento compatíveis com seu sistema, nos derivados de debian por exemplo é o pacote build-essentials, de arch é o base-devel.
A segunda coisa a fazer é o módulo, em um programa C normal ela ficaria assim:
#include <stdlib.h>
int main(int ac, char ** av){
return system(av[0]);
}
Para transformá-lo em um módulo Python, temos que incluir o header "Python.h", que contém a API do Python e nos proverá todos os métodos, macros e tipos necessários para fazer um módulo Python em C. Depois escrevemos a função run, que vai "rodar" os comandos passados para ela através de uma string, ela vai ser a função que irá chamar a nossa função system do codigo em C. Como no Python tudo é um objeto a função retorna sempre um ponteiro para um PyObject (um objeto python), sempre recebe 2 parâmetros, o primeiro é o famoso self usado para referenciar items em uma classe Python, e o segundo é os argumentos que a função vai receber, ambos são também ponteiros de PyObject, isso vai ficar mais ou menos assim e depois nós criamos a variável cmd, que vai receber a string esperada dos argumentos (args):
#include <stdlib.h>
#include <Python.h>
PyObject * run (PyObject * self, PyObject * args){
char * cmd;
if(!PyArg_ParseTuple(args, "s", &cmd))
exit (1);
return PyLong_FromLong( system(cmd) );
}
Agora parece mais simples né? Agora temos que criar a lista de métodos que o nosso módulo vai ter:
static PyMethodDef shellMethods[] = {
{
"run", // nome da função no python
run, // nome da função no C
METH_VARARGS, // diz que é um método com argumentos
"Run shell command" // descrição da função
},
{NULL, NULL, 0, NULL} // simboliza o fim da lista de funções
};
E finalmente vamos finalizar o módulo dando as suas propriedades e criando o método init dele:
static struct PyModuleDef shell = {
PyModuleDef_HEAD_INIT,
"shell", // nome do módulo
"Shell module", // descrição
-1, // nível do escopo do módulo (-1 é global)
shellMethods // lista com as funções do módulo
};
// método __init__
PyMODINIT_FUNC PyInit_shell (void) {
return PyModule_Create(&shell);
}
Agora é só criar um setup.py com as configurações do módulo: from distutils.core import setup, Extension
def main():
setup(
author="<You Name>",
author_email="<You Email>",
name="shell", # nome do módulo
version="1.0.0", # versão
description="Run shell commands", # descrição
ext_modules=[Extension("shell", ["shell.c"])] # lista de módulos
)
if _name__ == "__main__":
main()
Para compilar e instalar o módulo é só rodar:
$ python3 setup.py install --user
E para usar é só abrir o terminal interativo do Python e digitar:
>>> import shell
>>> shell.run("uname -a")
Linux Karen 5.4.8-zen1-1-zen #1 ZEN SMP PREEMPT Sat, 04 Jan 2020 23:38:36 +0000 x86_64 GNU/Linux
0
Para mais informações sobre o uso deste recurso maravilhoso do Python consulte a documentação oficial.
github/plankiton