Existe hoje muito código legado desenvolvido em diversas linguagens que pode ser aproveitado pelo Python, através de várias formas de integração.
Uma forma genérica de fazer isso é gerar uma biblioteca compartilhada (shared library) através do compilador da outra linguagem e fazer chamadas a funções que estão definidas na biblioteca.
Como a implementação original do Python é usando Linguagem C, é possível integrar Python e C nos dois sentidos:
Também é possível integrar o Python com Fortran usando o utilitário f2py, que faz parte do projeto NumPy.
A partir da versão 2.5, o Python incorporou o módulo ctypes, que implementa tipos compatíveis com os tipos usados pela linguagem C e permite evocar funções de bibliotecas compartilhadas.
O módulo provê várias formas de evocar funções. Funções que seguem a convenção de chamada stdcall, como a API do Windows, podem ser acessadas através da classe windll. Dynamic-link library (DLL) é a implementação de bibliotecas compartilhadas que são usadas no Windows.
Exemplo com windll:
import ctypes
# Evocando a caixa de mensagens do Windows
# Os argumentos são: janela pai, mensagem,
# título da janela e o tipo da janela.
# A função retorna um inteiro, que
# corresponde a que botão foi pressionado
i = ctypes.windll.user32.MessageBoxA(None,
'Teste de DLL!', 'Mensagem', 0)
# O resultado indica qual botão foi clicado
print i
Para funções que seguem a convenção de chamada cdecl, usada pela maioria dos compiladores C, existe a classe cdll. Para as passagens de argumentos por referência é preciso criar uma variável que funciona como um buffer para receber os resultados. Isso é necessário para receber strings, por exemplo.
Exemplo com cdll e buffer:
import ctypes
# msvcrt é a biblioteca com a maioria das funções
# padrões da linguagens C no Windows
# O Windows coloca automaticamente
# a extensão do arquivo
clib = ctypes.cdll.msvcrt
# Cria um buffer para receber o resultado
# a referência para o buffer será passada para
# a função, que preenche o buffer com o resultado
s = ctypes.c_buffer('\000', 40)
# sscanf() é uma função que extrai valores
# de uma string conforme uma mascara
clib.sscanf('Testando sscanf!\n',
'Testando %s!\n', s)
# Mostra o resultado
print s.value
É possível também evocar funções de bibliotecas compartilhadas no Linux:
import ctypes
# Carrega a biblioteca padrão C no Linux
# A extensão do arquivo precisa passada
# para a função LoadLibrary()
clib = ctypes.cdll.LoadLibrary("libc.so.6")
# Cria um buffer para receber o resultado
s = ctypes.c_buffer('\000', 40)
# Evoca a função sprintf
clib.sprintf(s, 'Testando %s\n', 'sprintf!')
# Mostra o resultado
print s.value
Através de bibliotecas compartilhadas é possível usar código desenvolvido em outras linguagens de uma maneira simples.
O módulo escrito em C deve utilizar as estruturas do Python (que estão definidas na API de interface) para se comunicar com o interpretador Python.
Exemplo:
// Arquivo: mymodule.c
// Python.h define as estruturas do Python em C
#include <Python.h>
// No Python, mesmo os erros sao objetos
static PyObject *MyModuleError;
// Chamando a funcao "system" em C
static PyObject *
mymodule_system(PyObject *self, PyObject *args)
{
const char *command;
int sts;
// "PyArg_ParseTuple" desempacota a tupla de parametros
// "s" significa que ele deve identificar uma string
if (!PyArg_ParseTuple(args, "s", &command))
// retornando NULL gera uma excessao
// caso falte parametros
return NULL;
// chamando "system":
sts = system(command);
// "Py_BuildValue" gera objetos que o Python conhece
// "i" significa inteiro
return Py_BuildValue("i", sts);
}
// Tabela que o Python consulta para resolver
// os metodos do modulo e pode ser usado
// tambem para gerar a documentacao
// por instrospeccao: dir(), help(),...
static PyMethodDef MyModuleMethods[] = {
{"system", mymodule_system, METH_VARARGS,
"Executa comandos externos."},
// Fim da tabela:
{NULL, NULL, 0, NULL}
};
// inicializacao do modulo:
PyMODINIT_FUNC
initmymodule(void)
{
// O modulo tambem e' um objeto
PyObject *m;
// "Py_InitModule" precisa do nome do modulo e da
// tabela de metodos
m = Py_InitModule("mymodule", MyModuleMethods);
// Erros...
MyModuleError = PyErr_NewException("mymodule.error",
NULL, NULL);
// "Py_INCREF" incrementa o numero de referencias do objeto
Py_INCREF(MyModuleError);
// "PyModule_AddObject" adiciona um objeto ao modulo
PyModule_AddObject(m, "error", MyModuleError);
}
Ao invés de compilar o módulo manualmente, use o Python para automatizar o processo. Primeiro, crie o script:
# Arquivo: setup.py
from distutils.core import setup, Extension
mymodule = Extension('mymodule', sources = ['mymodule.c'])
setup(name = 'MyPackage', version = '1.0',
description = 'My Package',
ext_modules = [mymodule])
E para compilar:
python setup.py build
O binário compilado será gerado dentro da pasta “build”. O módulo pode ser usado como qualquer outro módulo no Python (através de import).
O inverso também é possível. Um programa escrito em C pode evocar o interpretador Python seguindo três passos:
Exemplo:
// Arquivo: py_call.c
// Python.h com as definicoes para
// interagir com o interpretador
#include <Python.h>
int main()
{
// Inicializa interpretador Python
Py_Initialize();
// Executando codigo Python
PyRun_SimpleString("import os\n"
"for f in os.listdir('.'):\n"
" if os.path.isfile(f):\n"
" print f, ':', os.path.getsize(f)\n");
// Finaliza interpretador Python
Py_Finalize();
return 0;
}
Para compilar, é preciso passar a localização das headers e libraries do Python para o compilador C:
gcc -I/usr/include/python2.5 \
-L/usr/lib/python2.5/config \
-lpython2.5 -opy_call py_call.c
Observações: