Manufaturação industrial
Internet das coisas industrial | Materiais industriais | Manutenção e reparo de equipamentos | Programação industrial |
home  MfgRobots >> Manufaturação industrial >  >> Industrial programming >> python

Python - Programação de extensão com C

Página anteriorPróxima página
Qualquer código que você escrever usando qualquer linguagem compilada como C, C++ ou Java pode ser integrado ou importado em outro script Python. Este código é considerado como uma "extensão".

Um módulo de extensão Python nada mais é do que uma biblioteca C normal. Em máquinas Unix, essas bibliotecas geralmente terminam em .so (para objeto compartilhado). Em máquinas Windows, normalmente você vê .dll (para biblioteca vinculada dinamicamente).

Pré-requisitos para escrever extensões


Para começar a escrever sua extensão, você precisará dos arquivos de cabeçalho do Python.

Além disso, supõe-se que você tenha um bom conhecimento de C ou C++ para escrever qualquer extensão Python usando programação C.

Veja primeiro uma extensão Python


Para sua primeira olhada em um módulo de extensão Python, você precisa agrupar seu código em quatro partes -

O arquivo de cabeçalho Python.h


Você precisa incluir Python.h header em seu arquivo de origem C, que fornece acesso à API interna do Python usada para conectar seu módulo ao interpretador.

Certifique-se de incluir Python.h antes de quaisquer outros cabeçalhos que você possa precisar. Você precisa seguir as inclusões com as funções que deseja chamar do Python.

As funções C


As assinaturas da implementação C de suas funções sempre assumem uma das três formas a seguir -
static PyObject *MyFunction( PyObject *self, PyObject *args );

static PyObject *MyFunctionWithKeywords(PyObject *self,
                                 PyObject *args,
                                 PyObject *kw);

static PyObject *MyFunctionWithNoArgs( PyObject *self );

Cada uma das declarações anteriores retorna um objeto Python. Não existe vazio função em Python como existe em C. Se você não quiser que suas funções retornem um valor, retorne o equivalente em C de Nenhum do Python valor. Os cabeçalhos do Python definem uma macro, Py_RETURN_NONE, que faz isso para nós.

Os nomes de suas funções C podem ser o que você quiser, pois nunca são vistos fora do módulo de extensão. Eles são definidos como estático função.

Suas funções C geralmente são nomeadas combinando o módulo Python e os nomes da função, como mostrado aqui −
static PyObject *module_func(PyObject *self, PyObject *args) {
   /* Do your stuff here. */
   Py_RETURN_NONE;
}

Esta é uma função Python chamada func dentro do módulo módulo . Você colocará ponteiros para suas funções C na tabela de métodos para o módulo que geralmente vem a seguir em seu código-fonte.

A Tabela de Mapeamento de Métodos


Esta tabela de métodos é uma matriz simples de estruturas PyMethodDef. Essa estrutura se parece com isso -
struct PyMethodDef {
   char *ml_name;
   PyCFunction ml_meth;
   int ml_flags;
   char *ml_doc;
};

Aqui está a descrição dos membros desta estrutura -

Essa tabela precisa ser encerrada com um sentinela que consiste em valores NULL e 0 para os membros apropriados.

Exemplo


Para a função definida acima, temos a seguinte tabela de mapeamento de métodos -
static PyMethodDef module_methods[] = {
   { "func", (PyCFunction)module_func, METH_NOARGS, NULL },
   { NULL, NULL, 0, NULL }
};

A Função de Inicialização


A última parte do seu módulo de extensão é a função de inicialização. Esta função é chamada pelo interpretador Python quando o módulo é carregado. É necessário que a função seja denominada initMódulo , onde Módulo é o nome do módulo.

A função de inicialização precisa ser exportada da biblioteca que você construirá. Os cabeçalhos do Python definem PyMODINIT_FUNC para incluir os encantamentos apropriados para que isso aconteça para o ambiente específico em que estamos compilando. Tudo o que você precisa fazer é usá-lo ao definir a função.

Sua função de inicialização C geralmente tem a seguinte estrutura geral -
PyMODINIT_FUNC initModule() {
   Py_InitModule3(func, module_methods, "docstring...");
}

Aqui está a descrição de Py_InitModule3 função -

Juntando tudo isso se parece com o seguinte -
#include <Python.h>

static PyObject *module_func(PyObject *self, PyObject *args) {
   /* Do your stuff here. */
   Py_RETURN_NONE;
}

static PyMethodDef module_methods[] = {
   { "func", (PyCFunction)module_func, METH_NOARGS, NULL },
   { NULL, NULL, 0, NULL }
};

PyMODINIT_FUNC initModule() {
   Py_InitModule3(func, module_methods, "docstring...");
}

Exemplo


Um exemplo simples que faz uso de todos os conceitos acima -
#include <Python.h>

static PyObject* helloworld(PyObject* self) {
   return Py_BuildValue("s", "Hello, Python extensions!!");
}

static char helloworld_docs[] =
   "helloworld( ): Any message you want to put here!!\n";

static PyMethodDef helloworld_funcs[] = {
   {"helloworld", (PyCFunction)helloworld, 
      METH_NOARGS, helloworld_docs},
      {NULL}
};

void inithelloworld(void) {
   Py_InitModule3("helloworld", helloworld_funcs,
                  "Extension module example!");
}

Aqui o Py_BuildValue A função é usada para construir um valor Python. Salve o código acima no arquivo hello.c. Veríamos como compilar e instalar este módulo para ser chamado a partir do script Python.

Criação e instalação de extensões


Os distutils O pacote facilita muito a distribuição de módulos Python, tanto Python puro quanto módulos de extensão, de maneira padrão. Os módulos são distribuídos na forma de fonte e construídos e instalados por meio de um script de configuração geralmente chamado setup.py do seguinte modo.

Para o módulo acima, você precisa preparar o seguinte script setup.py -
from distutils.core import setup, Extension
setup(name='helloworld', version='1.0',  \
      ext_modules=[Extension('helloworld', ['hello.c'])])

Agora, use o seguinte comando, que executaria todas as etapas de compilação e vinculação necessárias, com os comandos e sinalizadores corretos do compilador e do vinculador, e copie a biblioteca dinâmica resultante em um diretório apropriado -
$ python setup.py install

Em sistemas baseados em Unix, você provavelmente precisará executar este comando como root para ter permissões para gravar no diretório de pacotes do site. Isso geralmente não é um problema no Windows.

Importando extensões


Depois de instalar sua extensão, você poderá importar e chamar essa extensão em seu script Python da seguinte maneira -
#!/usr/bin/python
import helloworld

print helloworld.helloworld()

Isso produziria o seguinte resultado -
Hello, Python extensions!!

Passando parâmetros de função


Como você provavelmente desejará definir funções que aceitem argumentos, você pode usar uma das outras assinaturas para suas funções C. Por exemplo, a seguinte função, que aceita algum número de parâmetros, seria definida assim −
static PyObject *module_func(PyObject *self, PyObject *args) {
   /* Parse args and do something interesting here. */
   Py_RETURN_NONE;
}

A tabela de métodos contendo uma entrada para a nova função ficaria assim −
static PyMethodDef module_methods[] = {
   { "func", (PyCFunction)module_func, METH_NOARGS, NULL },
   { "func", module_func, METH_VARARGS, NULL },
   { NULL, NULL, 0, NULL }
};

Você pode usar a API PyArg_ParseTuple para extrair os argumentos de um ponteiro PyObject passado para sua função C.

O primeiro argumento para PyArg_ParseTuple é o argumento args. Este é o objeto que você analisará . O segundo argumento é uma string de formato que descreve os argumentos como você espera que eles apareçam. Cada argumento é representado por um ou mais caracteres na string de formato da seguinte forma.
static PyObject *module_func(PyObject *self, PyObject *args) {
   int i;
   double d;
   char *s;

   if (!PyArg_ParseTuple(args, "ids", &i, &d, &s)) {
      return NULL;
   }
   
   /* Do something interesting here. */
   Py_RETURN_NONE;
}

Compilar a nova versão do seu módulo e importá-la permite que você invoque a nova função com qualquer número de argumentos de qualquer tipo −
module.func(1, s="three", d=2.0)
module.func(i=1, d=2.0, s="three")
module.func(s="three", d=2.0, i=1)

Você provavelmente pode criar ainda mais variações.

A PyArg_ParseTuple Função


Aqui está a assinatura padrão para PyArg_ParseTuple função -
int PyArg_ParseTuple(PyObject* tuple,char* format,...)

Esta função retorna 0 para erros e um valor diferente de 0 para sucesso. tupla é o PyObject* que foi o segundo argumento da função C. Aqui formato é uma string C que descreve argumentos obrigatórios e opcionais.

Aqui está uma lista de códigos de formato para PyArg_ParseTuple função -
Código tipo C Significado
c caractere Uma string Python de comprimento 1 se torna um caractere C.
d duplo Um float Python se torna um duplo C.
f flutuar Um float Python se torna um float C.
i int Um int Python se torna um int C.
l longo Um int do Python se torna um C long.
L longo longo Um int do Python se torna um C long
O PyObject* Obtém referência não NULL emprestada ao argumento Python.
s caractere* String Python sem nulos incorporados a C char*.
s# caracter*+int Qualquer string Python para endereço e comprimento C.
t# caracter*+int Buffer de segmento único somente leitura para endereço e comprimento C.
u Py_UNICODE* Python Unicode sem nulos incorporados em C.
u# Py_UNICODE*+int Qualquer endereço e comprimento Python Unicode C.
w# caracter*+int Ler/gravar buffer de segmento único no endereço e comprimento C.
z caractere* Assim como s, também aceita None (configura C char* como NULL).
z# caracter*+int Como s#, também aceita None (configura C char* como NULL).
(...) conforme ... Uma sequência Python é tratada como um argumento por item.
| Os argumentos a seguir são opcionais.
: Fim do formato, seguido do nome da função para mensagens de erro.
; Fim do formato, seguido por todo o texto da mensagem de erro.

Valores de retorno


Py_BuildValue recebe uma string de formato muito parecida com PyArg_ParseTuple faz. Em vez de passar os endereços dos valores que você está construindo, você passa os valores reais. Aqui está um exemplo mostrando como implementar uma função add -
static PyObject *foo_add(PyObject *self, PyObject *args) {
   int a;
   int b;

   if (!PyArg_ParseTuple(args, "ii", &a, &b)) {
      return NULL;
   }
   return Py_BuildValue("i", a + b);
}

É assim que ficaria se implementado em Python -
def add(a, b):
   return (a + b)

Você pode retornar dois valores de sua função da seguinte forma, isso seria capturado usando uma lista em Python.
static PyObject *foo_add_subtract(PyObject *self, PyObject *args) {
   int a;
   int b;

   if (!PyArg_ParseTuple(args, "ii", &a, &b)) {
      return NULL;
   }
   return Py_BuildValue("ii", a + b, a - b);
}

É assim que ficaria se implementado em Python -
def add_subtract(a, b):
   return (a + b, a - b)

O Py_BuildValue Função


Aqui está a assinatura padrão para Py_BuildValue função -
PyObject* Py_BuildValue(char* format,...)

Aqui formato é uma string C que descreve o objeto Python a ser construído. Os seguintes argumentos de Py_BuildValue são valores C a partir dos quais o resultado é construído. O PyObject* resultado é uma nova referência.

A tabela a seguir lista as strings de código comumente usadas, das quais zero ou mais são unidas no formato de string.
Código tipo C Significado
c caractere Um caractere C se torna uma string Python de comprimento 1.
d duplo Um duplo C se torna um float Python.
f flutuar Um float C se torna um float Python.
i int Um int C se torna um int Python.
l longo Um C long se torna um Python int.
N PyObject* Passa um objeto Python e rouba uma referência.
O PyObject* Passa um objeto Python e o INCREF normalmente.
O& converter+void* Conversão arbitrária
s caractere* C 0-terminated char* para string Python ou NULL para None.
s# caracter*+int C char* e length para string Python ou NULL para None.
u Py_UNICODE* String terminada em C-wide para Python Unicode ou NULL para None.
u# Py_UNICODE*+int String de C-wide e comprimento para Python Unicode ou NULL para None.
w# caracter*+int Ler/gravar buffer de segmento único no endereço e comprimento C.
z caractere* Assim como s, também aceita None (configura C char* como NULL).
z# caracter*+int Como s#, também aceita None (configura C char* como NULL).
(...) conforme ... Cria tupla Python a partir de valores C.
[...] conforme ... Cria uma lista Python a partir de valores C.
{...} conforme ... Cria dicionário Python a partir de valores C, alternando chaves e valores.

Code {...} constrói dicionários a partir de um número par de valores C, alternadamente chaves e valores. Por exemplo, Py_BuildValue("{issi}",23,"zig","zag",42) retorna um dicionário como o {23:'zig','zag':42} do Python.

python

  1. Programação Orientada a Objetos Python
  2. Instrução Python Print():Como imprimir com exemplos
  3. Função Python String strip () com EXEMPLO
  4. Python String count() com EXEMPLOS
  5. Python String format() Explique com EXEMPLOS
  6. Método Python String find() com exemplos
  7. Funções do Python Lambda com EXEMPLOS
  8. Função Python round() com EXEMPLOS
  9. Função Python map() com EXEMPLOS
  10. Python Timeit() com exemplos