FAQ sobre Extensão/Incorporação¶
Posso criar minhas próprias funções em C?¶
Sim, você pode construir módulos embutidos contendo funções, variáveis, exceções e até mesmo novos tipos em C. Isso é explicado no documento Estendendo e Incorporando o Interpretador Python.
A maioria dos livros intermediários ou avançados em Python também abordará esse tópico.
Posso criar minhas próprias funções em C++?¶
Sim, usando recursos de compatibilidade encontrados em C++. Coloque extern "C" { ... }
em torno dos arquivos de inclusão do Python e coloque extern "C"
antes de cada função que será chamada pelo interpretador do Python. Objetos globais ou estáticos em C++ com construtores provavelmente não são uma boa ideia.
Escrever C é difícil; há alguma alternativa?¶
Há um número de alternativas para escrever suas próprias extensões em C, dependendo daquilo que você está tentando fazer.
O Cython e o seu parente Pyrex são compiladores que aceitam uma forma de Python levemente modificada e geram o código C correspondente. Cython e Pyrex possibilitam escrever extensões sem que seja necessário aprender a usar a API C do Python.
Se você precisar interagir com alguma biblioteca C ou C++ que não é suportada por nenhuma extensão do Python no momento, você pode tentar envolver os tipos de dados e funções da biblioteca usando uma ferramenta como o SWIG. SIP, CXX Boost, e Weave são outras alternativas para criar invólucros de bibliotecas C++.
Como posso executar instruções arbitrárias de Python a partir de C?¶
A função mais alto-nível para isso é a PyRun_SimpleString()
, que recebe como único argumento uma string a ser executada no contexto do módulo __main__
e retorna 0
para sucesso e -1
quando uma exceção ocorrer (incluindo SyntaxError
). Se quiser mais controle, use PyRun_String()
; veja o código-fonte de PyRun_SimpleString()
em Python/pythonrun.c
.
Como posso executar e obter o resultado de uma expressão Python arbitrária a partir de C?¶
Chame a função PyRun_String()
da pergunta anterior passando Py_eval_input
como o símbolo de início; ela faz a análise sintática de uma expressão, a executa, e retorna o seu valor.
Como extraio valores em C a partir de um objeto Python?¶
Depende do tipo do objeto. Se for uma tupla, a PyTuple_Size()
retorna o seu comprimento e a PyTuple_GetItem()
retorna o item em um determinado índice. Listas têm funções similares, PyList_Size()
e PyList_GetItem()
.
Para bytes, a PyBytes_Size()
retorna o comprimento e a PyBytes_AsStringAndSize()
fornece um ponteiro para o seu valor e o seu comprimento. Note que objetos bytes em Python podem conter bytes nulos, de forma que a strlen()
do C não deve ser usada.
Para testar o tipo de um objeto, primeiramente se certifique de que ele não é NULL
, e então use PyBytes_Check()
, PyTuple_Check()
, PyList_Check()
, etc.
Também existe uma API alto-nível para objetos Python fornecida pela chamada interface “abstrata” – leia Include/abstract.h
para mais detalhes. Ela permite interagir com qualquer tipo de sequência Python usando chamadas como PySequence_Length()
, PySequence_GetItem()
, etc, além de vários outros protocolos úteis tais como números (PyNumber_Index()
e outros) e mapeamentos nas APIs PyMapping.
Como posso utilizar Py_BuildValue() para criar uma tupla de comprimento arbitrário?¶
Não é possível. Use a função PyTuple_Pack()
para isso.
Como eu chamo um método de um objeto a partir do C?¶
A função PyObject_CallMethod()
pode ser usada para chamar um método arbitrário de um objeto. Os parâmetros são o objeto, o nome do método a ser chamado, uma string de formato como a usada em Py_BuildValue()
, e os valores dos argumentos:
PyObject *
PyObject_CallMethod(PyObject *object, const char *method_name,
const char *arg_format, ...);
Isso funciona para qualquer objeto que tenha métodos – sejam eles embutidos ou definidos por usuário. Você fica então responsável por chamar Py_DECREF()
no valor de retorno.
Para chamar, por exemplo, o método “seek” de um objeto arquivo com argumentos 10, 0 (presumindo que “f” é o ponteiro para o objeto arquivo):
res = PyObject_CallMethod(f, "seek", "(ii)", 10, 0);
if (res == NULL) {
... ocorreu uma exceção ...
}
else {
Py_DECREF(res);
}
Note que a função PyObject_CallObject()
sempre recebe os argumentos da chamada como uma tupla, de forma que para chamar uma função sem argumentos deve-se passar “()” como formato, e para chamar uma função com 1 argumento, coloque-o entre parênteses, por exemplo “(i)”.
Como posso capturar a saída da função PyErr_Print() (ou qualquer outra coisa que escreva para stdout/stderr)?¶
Com código Python, defina um objeto que suporte o método write()
. Atribua esse objeto a sys.stdout
e sys.stderr
. Chame print_error, or simplesmente deixe o mecanismo padrão de traceback acontecer. Assim, a saída irá para onde quer que o seu método write()
a envie.
O jeito mais fácil de fazer isso é usar a classe io.StringIO
:
>>> import io, sys
>>> sys.stdout = io.StringIO()
>>> print('foo')
>>> print('hello world!')
>>> sys.stderr.write(sys.stdout.getvalue())
foo
hello world!
Um objeto personalizado para fazer a mesma coisa seria esse:
>>> import io, sys
>>> class StdoutCatcher(io.TextIOBase):
... def __init__(self):
... self.data = []
... def write(self, stuff):
... self.data.append(stuff)
...
>>> import sys
>>> sys.stdout = StdoutCatcher()
>>> print('foo')
>>> print('hello world!')
>>> sys.stderr.write(''.join(sys.stdout.data))
foo
hello world!
Como faço para acessar a partir do C um módulo escrito em Python?¶
Você pode obter um pointeiro para o objeto de módulo da seguinte maneira:
module = PyImport_ImportModule("<modulename>");
Se o módulo ainda não foi importado (isto é, ainda não aparece no sys.modules
), essa função vai inicializar o módulo; caso contrário, ela vai simplesmente retornar o valor de sys.modules["<modulename>"]
. Note que ela não adiciona o módulo a nenhum espaço de nomes – ela simplesmente garante que ele foi inicializado e colocado no sys.modules
.
Você pode então acessar os atributos do módulo (isto é, qualquer nome definido no módulo) assim:
attr = PyObject_GetAttrString(module, "<attrname>");
Chamar PyObject_SetAttrString()
para definir variáveis no módulo também funciona.
Como posso interagir com objetos C++ a partir do Python?¶
Dependendo das suas necessidades, há diversas abordagens. Para fazer isso manualmente, comece lendo o documento “Estendendo e Incorporando”. Note que, para o sistema Python em tempo de execução, não há muita diferença entre C e C++ – de forma que a estratégia de construir um novo tipo Python ao redor de uma estrutura C (ou ponteiro para uma) também funciona para objetos C++.
Para bibliotecas C++, veja Escrever C é difícil; há alguma alternativa?.
Adicionei um módulo usando o arquivo de Setup e o make falha; por quê?¶
O Setup deve terminar com uma quebra de linha; se não houver uma quebra de linha no final, o processo de compilação falha. (Consertar isso requer umas gambiarras feias em shell script, e esse bug é tão pequeno que o esforço não parece valer a pena.)
Como eu depuro uma extensão?¶
Ao usar o GDB com extensões carregadas dinamicamente, você não consegue definir um ponto de interrupção antes da sua extensão ser carregada.
No seu arquivo .gdbinit
(ou então interativamente), adicione o comando:
br _PyImport_LoadDynamicModule
Então, ao executar o GDB:
$ gdb /local/bin/python
gdb) run myscript.py
gdb) continue # repita até que a sua extensão seja carregada
gdb) finish # para que a sua extensão seja carregada
gdb) br myfunction.c:50
gdb) continue
Quero compilar um módulo Python no meu sistema Linux, mas alguns arquivos estão faltando. Por quê?¶
A maioria das versões empacotadas de Python omitem alguns arquivos necessários para compilar extensões do Python.
Em sistemas Red Hat, instale o RPM python3-devel para obter os arquivos necessários.
Para Debian, execute apt-get install python3-dev
.
Como posso distinguir “entrada incompleta” de “entrada inválida”?¶
Sometimes you want to emulate the Python interactive interpreter’s behavior, where it gives you a continuation prompt when the input is incomplete (e.g. you typed the start of an “if” statement or you didn’t close your parentheses or triple string quotes), but it gives you a syntax error message immediately when the input is invalid.
In Python you can use the codeop
module, which approximates the parser’s
behavior sufficiently. IDLE uses this, for example.
The easiest way to do it in C is to call PyRun_InteractiveLoop()
(perhaps
in a separate thread) and let the Python interpreter handle the input for
you. You can also set the PyOS_ReadlineFunctionPointer()
to point at your
custom input function. See Modules/readline.c
and Parser/myreadline.c
for more hints.
How do I find undefined g++ symbols __builtin_new or __pure_virtual?¶
To dynamically load g++ extension modules, you must recompile Python, relink it
using g++ (change LINKCC in the Python Modules Makefile), and link your
extension module using g++ (e.g., g++ -shared -o mymodule.so mymodule.o
).
Can I create an object class with some methods implemented in C and others in Python (e.g. through inheritance)?¶
Yes, you can inherit from built-in classes such as int
, list
,
dict
, etc.
The Boost Python Library (BPL, https://www.boost.org/libs/python/doc/index.html) provides a way of doing this from C++ (i.e. you can inherit from an extension class written in C++ using the BPL).