# Definindo módulos de extensão

Uma extensão C para CPython é uma biblioteca compartilhada (por exemplo, um arquivo `.so` no Linux, uma DLL `.pyd` no Windows), que pode ser carregada no processo Python (por exemplo, ela é compilada com configurações de compilador compatíveis) e que exporta uma função de inicialização.

Para ser importável por padrão (ou seja, por `importlib.machinery.ExtensionFileLoader`), a biblioteca compartilhada deve estar disponível em `sys.path` e deve ser nomeada após o nome do módulo mais uma extensão listada em `importlib.machinery.EXTENSION_SUFFIXES`.

Nota

A construção, o empacotamento e a distribuição de módulos de extensão são melhor realizados com ferramentas de terceiros e estão fora do escopo deste documento. Uma ferramenta adequada é o Setuptools, cuja documentação pode ser encontrada em https://setuptools.pypa.io/en/latest/setuptools.html.

Normalmente, a função de inicialização retorna uma definição de módulo inicializada usando `PyModuleDef_Init()`. Isso permite dividir o processo de criação em várias fases:

- Antes que qualquer código substancial seja executado, o Python pode determinar quais recursos o módulo oferece suporte e pode ajustar o ambiente ou se recusar a carregar uma extensão incompatível.

- Por padrão, o próprio Python cria o objeto módulo — ou seja, faz o equivalente a `object.__new__()` para classes. Ele também define atributos iniciais como `__package__` e `__loader__`.

- Depois, o objeto do módulo é inicializado usando código específico da extensão — o equivalente a `__init__()` em classes.

Isso é chamado de inicialização multifásica para diferenciá-lo do esquema legado (mas ainda suportado) de inicialização monofásica, em que a função de inicialização retorna um módulo totalmente construído. Consulte a seção inicialização monofásica abaixo para obter detalhes.

Alterado na versão 3.5: Adicionado suporte para inicialização multifásica (PEP 489).

## Várias instâncias de módulo

Por padrão, módulos de extensão não são singletons. Por exemplo, se a entrada `sys.modules` for removida e o módulo for reimportado, um novo objeto de módulo será criado e normalmente preenchido com novos métodos e tipos de objetos. O módulo antigo está sujeito à coleta de lixo normal. Isso reflete o comportamento dos módulos Python puros.

Instâncias adicionais do módulo podem ser criadas em subinterpretadores ou após a reinicialização do tempo de execução do Python (`Py_Finalize()` e `Py_Initialize()`). Nesses casos, compartilhar objetos Python entre instâncias do módulo provavelmente causaria travamentos ou comportamento indefinido.

Para evitar tais problemas, cada instância de um módulo de extensão deve ser isolada: alterações em uma instância não devem afetar implicitamente as outras, e todos os estados pertencentes ao módulo, incluindo referências a objetos Python, devem ser específicos de uma instância específica do módulo. Consulte Isolando módulos de extensão para obter mais detalhes e um guia prático.

Uma maneira mais simples de evitar esses problemas é levantar um erro na inicialização repetida.

Espera-se que todos os módulos ofereçam suporte a subinterpretador, ou então sinalizem explicitamente a falta de suporte. Isso geralmente é obtido por isolamento ou bloqueio de inicializações repetidas, como acima. Um módulo também pode ser limitado ao interpretador principal usando o slot `Py_mod_multiple_interpreters`.

## Função de inicialização

A função de inicialização definida por um módulo de extensão tem a seguinte assinatura:

PyObject *PyInit_modulename(void)

Seu nome deve ser `PyInit_<nome>`, com `<nome>` substituído pelo nome do módulo.

Para módulos com nomes com somente ASCII, a função deve ser nomeada `PyInit_<nome>`, com `<nome>` substituído pelo nome do módulo. Ao usar Inicialização multifásica, nomes de módulos não ASCII são permitidos. Neste caso, o nome da função de inicialização é `PyInitU_<nome>`, com `<nome>` codificado usando a codificação punycode do Python com hífenes substituídos por sublinhados. Em Python:

    def nome_func_iniciadora(nome):
        try:
            sufixo = b'_' + nome.encode('ascii')
        except UnicodeEncodeError:
            sufixo = b'U_' + nome.encode('punycode').replace(b'-', b'_')
        return b'PyInit' + sufixo

É recomendável definir a função de inicialização usando uma macro auxiliar:

PyMODINIT_FUNC

  Declara uma função de inicialização do módulo de extensão. Esta macro:

  - especifica o tipo de retorno PyObject*,

  - adiciona quaisquer declarações de vinculação especiais exigidas pela plataforma e

  - para C++, declara a função como `extern "C"`.

Por exemplo, um módulo chamado `spam` seria definido assim:

    static struct PyModuleDef spam_module = {
        .m_base = PyModuleDef_HEAD_INIT,
        .m_name = "spam",
        ...
    };

    PyMODINIT_FUNC
    PyInit_spam(void)
    {
        return PyModuleDef_Init(&spam_module);
    }

É possível exportar vários módulos de uma única biblioteca compartilhada, definindo várias funções de inicialização. No entanto, importá-los requer o uso de links simbólicos ou um importador personalizado, porque por padrão apenas a função correspondente ao nome do arquivo é encontrada. Veja a seção Multiple modules in one library na PEP 489 para detalhes.

A função de inicialização normalmente é o único item não `static` definido no código-fonte C do módulo.

## Inicialização multifásica

Normalmente, a função de inicialização (`PyInit_modulename`) retorna uma instância de `PyModuleDef` com `m_slots` não `NULL`. Antes de ser retornada, a instância `PyModuleDef` deve ser inicializada usando a seguinte função:

PyObject *PyModuleDef_Init(PyModuleDef *def)
  Parte da ABI Estável desde a versão 3.5.

  Garante que uma definição de módulo é um objeto Python devidamente inicializado que reporta corretamente seu tipo e uma contagem de referências.

  Retorna def convertido para `PyObject*`, ou `NULL` se ocorrer um erro.

  A chamada desta função é necessária para Inicialização multifásica. Ela não deve ser usada em outros contextos.

  Observe que o Python assume que as estruturas `PyModuleDef` são alocadas estaticamente. Esta função pode retornar uma nova referência ou uma referência emprestada; esta referência não deve ser liberada.

  Adicionado na versão 3.5.

## Inicialização monofásica legada

Atenção

A inicialização monofásica é um mecanismo legado para inicializar módulos de extensão, com desvantagens e falhas de projeto conhecidas. Os autores de módulos de extensão são incentivados a utilizar a inicialização multifásica.

Na inicialização monofásica, a função de inicialização (`PyInit_modulename`) deve criar, preencher e retornar um objeto de módulo. Isso normalmente é feito usando `PyModule_Create()` e funções como `PyModule_AddObjectRef()`.

A inicialização monofásica difere do padrão nas seguintes maneiras:

- Módulos monofásicos são, ou melhor, contêm, “singletons”.

  Quando o módulo é inicializado pela primeira vez, o Python salva o conteúdo do `__dict__` do módulo (ou seja, normalmente, as funções e os tipos do módulo).

  Para importações subsequentes, o Python não chama a função de inicialização novamente. Em vez disso, ele cria um novo objeto de módulo com um novo `__dict__` e copia o conteúdo salvo para ele. Por exemplo, dado um módulo monofásico `_testsinglephase` [1] que define uma função `sum` e uma classe de exceção `error`:

      >>> import sys
      >>> import _testsinglephase as one
      >>> del sys.modules['_testsinglephase']
      >>> import _testsinglephase as two
      >>> one is two
      False
      >>> one.__dict__ is two.__dict__
      False
      >>> one.sum is two.sum
      True
      >>> one.error is two.error
      True

  O comportamento exato deve ser considerado um detalhe da implementação do CPython.

- Para contornar o fato de que `PyInit_modulename` não aceita um argumento spec, parte do estado do mecanismo de importação é salvo e aplicado ao primeiro módulo adequado criado durante a chamada `PyInit_modulename`. Especificamente, quando um submódulo é importado, esse mecanismo adiciona o nome do pacote pai ao nome do módulo.

  Uma função monofásica `PyInit_modulename` deve criar “seu” objeto de módulo o mais rápido possível, antes que qualquer outro objeto de módulo possa ser criado.

- Nomes de módulos não ASCII (`PyInitU_modulename`) não são suportados.

- Módulos monofásicos oferecem suporte a funções de pesquisa de módulos como `PyState_FindModule()`.

[1]

`_testsinglephase` é um módulo interno usado no conjunto de autotestes do CPython; sua instalação pode ou não incluí-lo.