Continuamos o tópico de como chamar C / C ++ a partir do Python3 . Agora usamos as bibliotecas cffi , pybind11 . O método através de ctypes foi discutido em um artigo anterior.
C
Uma biblioteca de teste para demonstrar o trabalho com variáveis globais, estruturas e funções com argumentos de vários tipos.
test.h
typedef struct test_st_s test_st_t; extern int a; extern double b; extern char c; int func_ret_int(int val); double func_ret_double(double val); char *func_ret_str(char *val); char func_many_args(int val1, double val2, char val3, short val4); test_st_t *func_ret_struct(test_st_t *test_st); struct test_st_s { int val1; double val2; char val3; };
test.c
#include <stdio.h> #include <stdlib.h> #include "test.h" int a = 5; double b = 5.12345; char c = 'X'; int func_ret_int(int val) { printf("C get func_ret_int: %d\n", val); return val; } double func_ret_double(double val) { printf("C get func_ret_double: %f\n", val); return val; } char * func_ret_str(char *val) { printf("C get func_ret_str: %s\n", val); return val; } char func_many_args(int val1, double val2, char val3, short val4) { printf("C get func_many_args: int - %d, double - %f, char - %c, short - %d\n", val1, val2, val3, val4); return val3; } test_st_t * func_ret_struct(test_st_t *test_st) { if (test_st) { printf("C get test_st: val1 - %d, val2 - %f, val3 - %c\n", test_st->val1, test_st->val2, test_st->val3); } return test_st; }
A biblioteca é exatamente a mesma do artigo ctypes .
CFFI
Esta é uma biblioteca para trabalhar exclusivamente com C. A partir da descrição desta biblioteca:
Interaja com quase qualquer código C do Python
Parte disso foi quase encontrada.
Para o experimento, a versão 1.12.3 foi usada , você pode ler sobre isso aqui .
Um pouco sobre esta biblioteca em duas palavras, o CFFI gera sua ligação no topo da nossa biblioteca e a compila em uma biblioteca com a qual trabalharemos.
Instalação
pip3 install cffi
Assembléia
O script de compilação que coletará a ligação em torno de nossa biblioteca.
build.py
import os import cffi if __name__ == "__main__": ffi = cffi.FFI()
Python
Um exemplo de trabalho com C do Python através do CFFI :
from cffi import FFI import sys import time
Para trabalhar com código C ++ , você precisa escrever uma ligação C para ele. O artigo sobre o método através de ctypes descreve como fazer isso. Link abaixo.
Prós e contras do CFFI
Prós :
- sintaxe simples quando usada em Python
- não há necessidade de recompilar a biblioteca de origem
Contras :
pybind11
O pybind11, por outro lado, foi projetado especificamente para trabalhar com C ++ . A versão 2.3.0 foi usada para o experimento, você pode ler sobre isso aqui . Ela não coleta fontes C, então eu as traduzi em fontes C ++.
Instalação
pip3 install pybind11
Assembléia
Precisamos escrever um script de construção para nossa biblioteca.
build.py
import pybind11 from distutils.core import setup, Extension ext_modules = [ Extension( '_test',
Nós o executamos:
python3 setup.py build --build-lib=./lib
C ++
Na fonte da biblioteca, você precisa adicionar:
namespace py = pybind11;
Python
Um exemplo de trabalho com C do Python via pybind11 :
import sys import time
Prós e contras de pybind11
Prós :
- sintaxe simples quando usada em Python
Contras :
- você precisa editar fontes C ++ ou escrever uma ligação para elas
- é necessário coletar a biblioteca necessária da fonte
O tempo médio de execução do teste em cada método com 1000 inicia:
- ctypes: - 0.0004987692832946777 segundos ---
- CFFI: - 0.00038521790504455566 segundos ---
- pybind: - 0.0004547207355499268 segundos ---
+, - porque os resultados foram ligeiramente diferentes a cada vez. Além disso, o tempo gasto na impressão, que eu estava com preguiça de desligar (considere esse tempo uma constante, porque será o mesmo em todos os testes). Mas, ainda assim, há uma diferença de horário nas chamadas de função e na obtenção dos resultados delas.
Referências