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).
