Introdução

A Interface de Programação de Aplicações (API) para Python fornece aos programadores C e C++ acesso ao interpretador Python em uma variedade de níveis. A API pode ser usada igualmente em C++, mas, para abreviar, geralmente é chamada de API Python/C. Existem dois motivos fundamentalmente diferentes para usar a API Python/C. A primeira razão é escrever módulos de extensão para propósitos específicos; esses são módulos C que estendem o interpretador Python. Este é provavelmente o uso mais comum. O segundo motivo é usar Python como um componente em uma aplicação maior; esta técnica é geralmente referida como incorporação Python em uma aplicação.

Writing an extension module is a relatively well-understood process, where a “cookbook” approach works well. There are several tools that automate the process to some extent. While people have embedded Python in other applications since its early existence, the process of embedding Python is less straightforward than writing an extension.

Muitas funções da API são úteis independentemente de você estar incorporando ou estendendo o Python; além disso, a maioria das aplicações que incorporam Python também precisará fornecer uma extensão customizada, portanto, é provavelmente uma boa ideia se familiarizar com a escrita de uma extensão antes de tentar incorporar Python em uma aplicação real.

Incluir Arquivos

Todas as definições de função, tipo e macro necessárias para usar a API Python/C estão incluídas em seu código pela seguinte linha:

#include "Python.h"

Isso implica a inclusão dos seguintes cabeçalhos padrão: <stdio.h>, <string.h>, <errno.h>, <limits.h>, <assert.h> e <stdlib.h> (se disponível).

Nota

Uma vez que Python pode definir algumas definições de pré-processador que afetam os cabeçalhos padrão em alguns sistemas, você deve incluir Python.h antes de quaisquer cabeçalhos padrão serem incluídos.

Todos os nomes visíveis ao usuário definidos por Python.h (exceto aqueles definidos pelos cabeçalhos padrão incluídos) têm um dos prefixos Py ou _Py. Nomes começando com _Py são para uso interno pela implementação Python e não devem ser usados por escritores de extensão. Os nomes dos membros da estrutura não têm um prefixo reservado.

Important: user code should never define names that begin with Py or _Py. This confuses the reader, and jeopardizes the portability of the user code to future Python versions, which may define additional names beginning with one of these prefixes.

Os arquivos de cabeçalho são normalmente instalados com Python. No Unix, eles estão localizados nos diretórios prefix/include/pythonversion/ e exec_prefix/include/pythonversion/, onde prefix e exec_prefix são definidos pelos parâmetros correspondentes ao script configure e version do Python é '%d.%d' % sys.version_info[:2]. No Windows, os cabeçalhos são instalados em prefix/include, onde prefix é o diretório de instalação especificado para o instalador.

Para incluir os cabeçalhos, coloque os dois diretórios (se diferentes) no caminho de pesquisa do compilador para as inclusões. Não coloque os diretórios pais no caminho de busca e então use #include <pythonX.Y/Python.h>; isto irá quebrar em compilações multiplataforma, uma vez que os cabeçalhos independentes da plataforma em prefix incluem os cabeçalhos específicos da plataforma de exec_prefix.

C++ users should note that though the API is defined entirely using C, the header files do properly declare the entry points to be extern "C", so there is no need to do anything special to use the API from C++.

Objetos, tipos e contagens de referência

Most Python/C API functions have one or more arguments as well as a return value of type PyObject*. This type is a pointer to an opaque data type representing an arbitrary Python object. Since all Python object types are treated the same way by the Python language in most situations (e.g., assignments, scope rules, and argument passing), it is only fitting that they should be represented by a single C type. Almost all Python objects live on the heap: you never declare an automatic or static variable of type PyObject, only pointer variables of type PyObject* can be declared. The sole exception are the type objects; since these must never be deallocated, they are typically static PyTypeObject objects.

Todos os objetos Python (mesmo inteiros Python) têm um tipo e uma contagem de referências. O tipo de um objeto determina que tipo de objeto ele é (por exemplo, um número inteiro, uma lista ou uma função definida pelo usuário; existem muitos mais, conforme explicado em A hierarquia de tipos padrão). Para cada um dos tipos conhecidos, há uma macro para verificar se um objeto é desse tipo; por exemplo, PyList_Check(a) é verdadeiro se (e somente se) o objeto apontado por a for uma lista Python.

Contagens de referência

A contagem de referência é importante porque os computadores de hoje têm um tamanho de memória finito (e geralmente muito limitado); Conta quantos lugares diferentes existem que têm uma referência a um objeto. Esse local poderia ser outro objeto, uma variável C global (ou estática) ou uma variável local em alguma função C. Quando a contagem de referência de um objeto se torna zero, o objeto é desalocado. Se contiver referências a outros objetos, sua contagem de referência será diminuída. Esses outros objetos podem ser desalocados, por sua vez, se esse decremento fizer com que sua contagem de referência se torne zero e assim por diante. (Há um problema óbvio com objetos que fazem referência um ao outro aqui; por enquanto, a solução é “não faça isso”).

As contagens de referências são sempre manipuladas explicitamente. A maneira normal é usar a macro Py_INCREF() para incrementar a contagem de referências de um objeto em um, e Py_DECREF() para diminuí-la em um. A macro Py_DECREF() é consideravelmente mais complexa que a “incref”, uma vez que deve verificar se a contagem de referências torna-se zero e então fazer com que o desalocador do objeto seja chamado. O desalocador é um ponteiro de função contido na estrutura de tipo do objeto. O desalocador específico do tipo se encarrega de diminuir as contagens de referências para outros objetos contidos no objeto se este for um tipo de objeto composto, como uma lista, bem como realizar qualquer finalização adicional necessária. Não há chance de que a contagem de referências possa estourar; pelo menos tantos bits são usados ​​para manter a contagem de referência quanto há locais de memória distintos na memória virtual (assumindo sizeof(Py_ssize_t) >= sizeof(void*)). Portanto, o incremento da contagem de referências é uma operação simples.

Não é necessário incrementar a contagem de referências de um objeto para cada variável local que contém um ponteiro para um objeto. Em teoria, a contagem de referências do objeto aumenta em um quando a variável é feita para apontar para ele e diminui em um quando a variável sai do escopo. No entanto, esses dois se cancelam, portanto, no final, a contagem de referências não mudou. A única razão real para usar a contagem de referências é evitar que o objeto seja desalocado enquanto nossa variável estiver apontando para ele. Se sabemos que existe pelo menos uma outra referência ao objeto que vive pelo menos tanto quanto nossa variável, não há necessidade de incrementar a contagem de referências temporariamente. Uma situação importante em que isso ocorre é em objetos que são passados como argumentos para funções C em um módulo de extensão que são chamados de Python; o mecanismo de chamada garante manter uma referência a todos os argumentos durante a chamada.

However, a common pitfall is to extract an object from a list and hold on to it for a while without incrementing its reference count. Some other operation might conceivably remove the object from the list, decrementing its reference count and possible deallocating it. The real danger is that innocent-looking operations may invoke arbitrary Python code which could do this; there is a code path which allows control to flow back to the user from a Py_DECREF(), so almost any operation is potentially dangerous.

Uma abordagem segura é sempre usar as operações genéricas (funções cujo nome começa com PyObject_, PyNumber_, PySequence_ or PyMapping_). Essas operações sempre incrementam a contagem de referências do objeto que retornam. Isso deixa o chamador com a responsabilidade de chamar Py_DECREF() quando terminar com o resultado; isso logo se torna uma segunda natureza.

Detalhes da contagem de referência

O comportamento da contagem de referências de funções na API Python/C é melhor explicado em termos de propriedade de referências. A propriedade pertence às referências, nunca aos objetos (os objetos não são possuídos: eles são sempre compartilhados). “Possuir uma referência” significa ser responsável por chamar Py_DECREF nela quando a referência não for mais necessária. A propriedade também pode ser transferida, o que significa que o código que recebe a propriedade da referência torna-se responsável por eventualmente efetuar um decref nela chamando Py_DECREF() ou Py_XDECREF() quando não é mais necessário — ou passando essa responsabilidade (geralmente para o responsável pela chamada). Quando uma função passa a propriedade de uma referência para seu chamador, diz-se que o chamador recebe uma nova referência. Quando nenhuma propriedade é transferida, diz-se que o chamador toma emprestado a referência. Nada precisa ser feito para uma referência emprestada.

Por outro lado, quando uma função de chamada passa uma referência a um objeto, há duas possibilidades: a função rouba uma referência ao objeto, ou não. Roubar uma referência significa que quando você passa uma referência para uma função, essa função assume que agora ela possui essa referência e você não é mais responsável por ela.

Poucas funções roubam referências; as duas exceções notáveis são PyList_SetItem() e PyTuple_SetItem(), que roubam uma referência para o item (mas não para a tupla ou lista na qual o item é colocado!). Essas funções foram projetadas para roubar uma referência devido a um idioma comum para preencher uma tupla ou lista com objetos recém-criados; por exemplo, o código para criar a tupla (1, 2, "three") pode ser parecido com isto (esquecendo o tratamento de erros por enquanto; uma maneira melhor de codificar isso é mostrada abaixo):

PyObject *t;

t = PyTuple_New(3);
PyTuple_SetItem(t, 0, PyLong_FromLong(1L));
PyTuple_SetItem(t, 1, PyLong_FromLong(2L));
PyTuple_SetItem(t, 2, PyUnicode_FromString("three"));

Aqui, PyLong_FromLong() retorna uma nova referência que é imediatamente roubada por PyTuple_SetItem(). Quando você quiser continuar usando um objeto, embora a referência a ele seja roubada, use Py_INCREF() para obter outra referência antes de chamar a função de roubo de referência.

A propósito, PyTuple_SetItem() é a única maneira de definir itens de tupla; PySequence_SetItem() e PyObject_SetItem() se recusam a fazer isso, pois tuplas são um tipo de dados imutável. Você só deve usar PyTuple_SetItem() para tuplas que você mesmo está criando.

O código equivalente para preencher uma lista pode ser escrita usando PyList_New() e PyList_SetItem().

No entanto, na prática, você raramente usará essas maneiras de criar e preencher uma tupla ou lista. Existe uma função genérica, Py_BuildValue(), que pode criar objetos mais comuns a partir de valores C, dirigidos por uma string de formato. Por exemplo, os dois blocos de código acima podem ser substituídos pelos seguintes (que também cuidam da verificação de erros):

PyObject *tuple, *list;

tuple = Py_BuildValue("(iis)", 1, 2, "three");
list = Py_BuildValue("[iis]", 1, 2, "three");

É muito mais comum usar PyObject_SetItem() e amigos com itens cujas referências você está apenas pegando emprestado, como argumentos que foram passados para a função que você está escrevendo. Nesse caso, o comportamento deles em relação às contagens de referência é muito mais são, já que você não precisa incrementar uma contagem de referências para que possa dar uma referência (“mande-a ser roubada”). Por exemplo, esta função define todos os itens de uma lista (na verdade, qualquer sequência mutável) para um determinado item:

int
set_all(PyObject *target, PyObject *item)
{
    Py_ssize_t i, n;

    n = PyObject_Length(target);
    if (n < 0)
        return -1;
    for (i = 0; i < n; i++) {
        PyObject *index = PyLong_FromSsize_t(i);
        if (!index)
            return -1;
        if (PyObject_SetItem(target, index, item) < 0) {
            Py_DECREF(index);
            return -1;
        }
        Py_DECREF(index);
    }
    return 0;
}

A situação é ligeiramente diferente para os valores de retorno da função. Embora passar uma referência para a maioria das funções não altere suas responsabilidades de propriedade para aquela referência, muitas funções que retornam uma referência a um objeto fornecem a propriedade da referência. O motivo é simples: em muitos casos, o objeto retornado é criado instantaneamente e a referência que você obtém é a única referência ao objeto. Portanto, as funções genéricas que retornam referências a objetos, como PyObject_GetItem() e PySequence_GetItem(), sempre retornam uma nova referência (o chamador torna-se o dono da referência).

É importante perceber que se você possui uma referência retornada por uma função depende de qual função você chama apenas — a plumagem (o tipo do objeto passado como um argumento para a função) não entra nela! Assim, se você extrair um item de uma lista usando PyList_GetItem(), você não possui a referência — mas se obtiver o mesmo item da mesma lista usando PySequence_GetItem() (que leva exatamente os mesmos argumentos), você possui uma referência ao objeto retornado.

Aqui está um exemplo de como você poderia escrever uma função que calcula a soma dos itens em uma lista de inteiros; uma vez usando PyList_GetItem(), e uma vez usando PySequence_GetItem().

long
sum_list(PyObject *list)
{
    Py_ssize_t i, n;
    long total = 0, value;
    PyObject *item;

    n = PyList_Size(list);
    if (n < 0)
        return -1; /* Not a list */
    for (i = 0; i < n; i++) {
        item = PyList_GetItem(list, i); /* Can't fail */
        if (!PyLong_Check(item)) continue; /* Skip non-integers */
        value = PyLong_AsLong(item);
        if (value == -1 && PyErr_Occurred())
            /* Integer too big to fit in a C long, bail out */
            return -1;
        total += value;
    }
    return total;
}
long
sum_sequence(PyObject *sequence)
{
    Py_ssize_t i, n;
    long total = 0, value;
    PyObject *item;
    n = PySequence_Length(sequence);
    if (n < 0)
        return -1; /* Has no length */
    for (i = 0; i < n; i++) {
        item = PySequence_GetItem(sequence, i);
        if (item == NULL)
            return -1; /* Not a sequence, or other failure */
        if (PyLong_Check(item)) {
            value = PyLong_AsLong(item);
            Py_DECREF(item);
            if (value == -1 && PyErr_Occurred())
                /* Integer too big to fit in a C long, bail out */
                return -1;
            total += value;
        }
        else {
            Py_DECREF(item); /* Discard reference ownership */
        }
    }
    return total;
}

Tipos

There are few other data types that play a significant role in the Python/C API; most are simple C types such as int, long, double and char*. A few structure types are used to describe static tables used to list the functions exported by a module or the data attributes of a new object type, and another is used to describe the value of a complex number. These will be discussed together with the functions that use them.

Exceções

O programador Python só precisa lidar com exceções se o tratamento de erros específico for necessário; as exceções não tratadas são propagadas automaticamente para o chamador, depois para o chamador e assim por diante, até chegarem ao interpretador de nível superior, onde são relatadas ao usuário acompanhadas por um traceback (situação da pilha de execução).

For C programmers, however, error checking always has to be explicit. All functions in the Python/C API can raise exceptions, unless an explicit claim is made otherwise in a function’s documentation. In general, when a function encounters an error, it sets an exception, discards any object references that it owns, and returns an error indicator. If not documented otherwise, this indicator is either NULL or -1, depending on the function’s return type. A few functions return a Boolean true/false result, with false indicating an error. Very few functions return no explicit error indicator or have an ambiguous return value, and require explicit testing for errors with PyErr_Occurred(). These exceptions are always explicitly documented.

Exception state is maintained in per-thread storage (this is equivalent to using global storage in an unthreaded application). A thread can be in one of two states: an exception has occurred, or not. The function PyErr_Occurred() can be used to check for this: it returns a borrowed reference to the exception type object when an exception has occurred, and NULL otherwise. There are a number of functions to set the exception state: PyErr_SetString() is the most common (though not the most general) function to set the exception state, and PyErr_Clear() clears the exception state.

The full exception state consists of three objects (all of which can be NULL): the exception type, the corresponding exception value, and the traceback. These have the same meanings as the Python result of sys.exc_info(); however, they are not the same: the Python objects represent the last exception being handled by a Python tryexcept statement, while the C level exception state only exists while an exception is being passed on between C functions until it reaches the Python bytecode interpreter’s main loop, which takes care of transferring it to sys.exc_info() and friends.

Observe que a partir do Python 1.5, a maneira preferida e segura para thread para acessar o estado de exceção do código Python é chamar a função sys.exc_info(), que retorna o estado de exceção por thread para o código Python. Além disso, a semântica de ambas as maneiras de acessar o estado de exceção mudou, de modo que uma função que captura uma exceção salvará e restaurará o estado de exceção de seu segmento de modo a preservar o estado de exceção de seu chamador. Isso evita bugs comuns no código de tratamento de exceções causados por uma função aparentemente inocente sobrescrevendo a exceção sendo tratada; também reduz a extensão da vida útil frequentemente indesejada para objetos que são referenciados pelos quadros de pilha no traceback.

Como princípio geral, uma função que chama outra função para realizar alguma tarefa deve verificar se a função chamada levantou uma exceção e, em caso afirmativo, passar o estado da exceção para seu chamador. Ele deve descartar todas as referências de objeto que possui e retornar um indicador de erro, mas não deve definir outra exceção — que sobrescreveria a exceção que acabou de ser gerada e perderia informações importantes sobre a causa exata do erro.

Um exemplo simples de detecção de exceções e transmiti-las é mostrado no exemplo sum_sequence() acima. Acontece que este exemplo não precisa limpar nenhuma referência de propriedade quando detecta um erro. A função de exemplo a seguir mostra alguma limpeza de erro. Primeiro, para lembrar por que você gosta de Python, mostramos o código Python equivalente:

def incr_item(dict, key):
    try:
        item = dict[key]
    except KeyError:
        item = 0
    dict[key] = item + 1

Aqui está o código C correspondente, em toda sua glória:

int
incr_item(PyObject *dict, PyObject *key)
{
    /* Objects all initialized to NULL for Py_XDECREF */
    PyObject *item = NULL, *const_one = NULL, *incremented_item = NULL;
    int rv = -1; /* Return value initialized to -1 (failure) */

    item = PyObject_GetItem(dict, key);
    if (item == NULL) {
        /* Handle KeyError only: */
        if (!PyErr_ExceptionMatches(PyExc_KeyError))
            goto error;

        /* Clear the error and use zero: */
        PyErr_Clear();
        item = PyLong_FromLong(0L);
        if (item == NULL)
            goto error;
    }
    const_one = PyLong_FromLong(1L);
    if (const_one == NULL)
        goto error;

    incremented_item = PyNumber_Add(item, const_one);
    if (incremented_item == NULL)
        goto error;

    if (PyObject_SetItem(dict, key, incremented_item) < 0)
        goto error;
    rv = 0; /* Success */
    /* Continue with cleanup code */

 error:
    /* Cleanup code, shared by success and failure path */

    /* Use Py_XDECREF() to ignore NULL references */
    Py_XDECREF(item);
    Py_XDECREF(const_one);
    Py_XDECREF(incremented_item);

    return rv; /* -1 for error, 0 for success */
}

This example represents an endorsed use of the goto statement in C! It illustrates the use of PyErr_ExceptionMatches() and PyErr_Clear() to handle specific exceptions, and the use of Py_XDECREF() to dispose of owned references that may be NULL (note the 'X' in the name; Py_DECREF() would crash when confronted with a NULL reference). It is important that the variables used to hold owned references are initialized to NULL for this to work; likewise, the proposed return value is initialized to -1 (failure) and only set to success after the final call made is successful.

Incorporando Python

A única tarefa importante com a qual apenas os incorporadores (em oposição aos escritores de extensão) do interpretador Python precisam se preocupar é a inicialização e, possivelmente, a finalização do interpretador Python. A maior parte da funcionalidade do interpretador só pode ser usada após a inicialização do interpretador.

A função de inicialização básica é Py_Initialize(). Isso inicializa a tabela de módulos carregados e cria os módulos fundamentais builtins, __main__ e sys. Ela também inicializa o caminho de pesquisa de módulos (sys.path).

Py_Initialize() não define a “lista de argumentos de script” (sys.argv). Se esta variável for necessária para o código Python que será executado posteriormente, ela deve ser definida explicitamente com uma chamada com PySys_SetArgvEx(argc, argv, updatepath) após a chamada de Py_Initialize().

Na maioria dos sistemas (em particular, no Unix e no Windows, embora os detalhes sejam ligeiramente diferentes), Py_Initialize() calcula o caminho de pesquisa do módulo com base em sua melhor estimativa para a localização do executável do interpretador Python padrão, assumindo que a biblioteca Python é encontrada em um local fixo em relação ao executável do interpretador Python. Em particular, ele procura por um diretório chamado lib/pythonX.Y relativo ao diretório pai onde o executável chamado python é encontrado no caminho de pesquisa de comandos do shell (a variável de ambiente PATH).

Por exemplo, se o executável Python for encontrado em /usr/local/bin/python, ele presumirá que as bibliotecas estão em /usr/local/lib/pythonX.Y. (Na verdade, este caminho particular também é o local reserva, usado quando nenhum arquivo executável chamado python é encontrado ao longo de PATH.) O usuário pode substituir este comportamento definindo a variável de ambiente PYTHONHOME, ou insira diretórios adicionais na frente do caminho padrão definindo PYTHONPATH.

A aplicação de incorporação pode orientar a pesquisa chamando Py_SetProgramName(file) antes de chamar Py_Initialize(). Observe que PYTHONHOME ainda substitui isso e PYTHONPATH ainda é inserido na frente do caminho padrão. Uma aplicação que requer controle total deve fornecer sua própria implementação de Py_GetPath(), Py_GetPrefix(), Py_GetExecPrefix() e Py_GetProgramFullPath() (todas definidas em Modules/getpath.c).

Às vezes, é desejável “desinicializar” o Python. Por exemplo, a aplicação pode querer iniciar novamente (fazer outra chamada para Py_Initialize()) ou a aplicação simplesmente termina com o uso de Python e deseja liberar memória alocada pelo Python. Isso pode ser feito chamando Py_FinalizeEx(). A função Py_IsInitialized() retorna verdadeiro se o Python está atualmente no estado inicializado. Mais informações sobre essas funções são fornecidas em um capítulo posterior. Observe que Py_FinalizeEx() não libera toda a memória alocada pelo interpretador Python, por exemplo, a memória alocada por módulos de extensão atualmente não pode ser liberada.

Construções de Depuração

Python pode ser compilado com várias macros para permitir verificações extras do interpretador e módulos de extensão. Essas verificações tendem a adicionar uma grande quantidade de sobrecarga ao tempo de execução, portanto, não são habilitadas por padrão.

Uma lista completa dos vários tipos de compilações de depuração está no arquivo Misc/SpecialBuilds.txt na distribuição do código-fonte do Python. Estão disponíveis compilações que oferecem suporte ao rastreamento de contagens de referências, depuração do alocador de memória ou criação de perfil de baixo nível do loop do interpretador principal. Apenas as compilações usadas com mais frequência serão descritas no restante desta seção.

Compilar o interpretador com a macro Py_DEBUG definida produz o que geralmente se entende por “uma compilação de depuração” do Python. Py_DEBUG é habilitada na compilação Unix adicionando --with-pydebug ao comando ./configure. Também está implícito na presença da macro não específica do Python _DEBUG. Quando Py_DEBUG está habilitado na compilação do Unix, a otimização do compilador é desabilitada.

Além da depuração de contagem de referência descrita abaixo, as seguintes verificações extras são executadas:

  • Verificações extras são adicionadas ao alocador de objetos.

  • Verificações extras são adicionadas ao analisador e ao compilador.

  • Downcasts de tipos amplos para tipos restritos são verificados quanto à perda de informações.

  • Uma série de asserções são adicionadas ao dicionário e implementações definidas. Além disso, o objeto definido adquire um método test_c_api().

  • As verificações de integridade dos argumentos de entrada são adicionadas à criação de quadros.

  • O armazenamento para ints é inicializado com um padrão inválido conhecido para capturar a referência a dígitos não inicializados.

  • O rastreamento de baixo nível e a verificação de exceções extras são adicionados à máquina virtual de tempo de execução.

  • Verificações extras são adicionadas à implementação da arena de memória.

  • Depuração extra é adicionada ao módulo de thread.

Pode haver verificações adicionais não mencionadas aqui.

Definir Py_TRACE_REFS habilita o rastreamento de referência. Quando definida, uma lista circular duplamente vinculada de objetos ativos é mantida adicionando dois campos extras a cada PyObject. As alocações totais também são rastreadas. Ao sair, todas as referências existentes são impressas. (No modo interativo, isso acontece após cada instrução executada pelo interpretador.) Implicado por Py_DEBUG.

Consulte Misc/SpecialBuilds.txt na distribuição do código-fonte Python para informações mais detalhadas.