Protocolo de chamada¶
O CPython permite dois protocolos de chamada: tp_call e vectorcall.
O protocolo tp_call¶
Instâncias de classe que definem tp_call são chamáveis. A assinatura do slot é:
PyObject *tp_call(PyObject *callable, PyObject *args, PyObject *kwargs);
Uma chamada é feita usando uma tupla para os argumentos posicionais e um dicionário para os argumentos nomeados, similar a callable(*args, **kwargs) no Python. args não pode ser nulo (utilize uma tupla vazia se não houver argumentos), mas kwargs pode ser NULL se não houver argumentos nomeados.
Esta convenção não é somente usada por tp_call: tp_new e tp_init também passam argumento dessa forma.
Para chamar um objeto, use PyObject_Call() ou outra API de chamada.
O protocolo vectorcall¶
Novo na versão 3.9.
O protocolo vectorcall foi introduzido pela PEP 590 como um protocolo adicional para tornar invocações mais eficientes.
Como regra de ouro, CPython vai preferir o vectorcall para chamadas internas se o chamável suportar. Entretanto, isso não é uma regra rígida. Ademais, alguma extensões de terceiros usam tp_call diretamente (em vez de utilizar PyObject_Call()). Portanto, uma classe que suporta vectorcall precisa também implementar tp_call. Além disso, o chamável precisa se comportar da mesma forma independe de qual protocolo é utilizado. A forma recomendada de alcançar isso é definindo tp_call para PyVectorcall_Call(). Vale a pena repetir:
Aviso
Uma classe que suporte vectorcall também precisa implementar tp_call com a mesma semântica.
Uma classe não deve implementar vectorcall se for mais lento que tp_call. Por exemplo, se o chamador precisa converter os argumentos para uma tupla args e um dicionário kwargs de qualquer forma, então não é necessário implementar vectorcall.
Classes podem implementar o protocolo de chamada de vetor ativando a flag Py_TPFLAGS_HAVE_VECTORCALL e configurando tp_vectorcall_offset para o offset dentro da estrutura do objeto onde uma vectorcallfunc aparece. Este é um ponteiro para uma função com a seguinte assinatura:
-
typedef PyObject *(*
vectorcallfunc)(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwnames)¶
callable é o objeto sendo chamado.
- args é um array C formado pelos argumentos posicionais seguidos de
valores dos argumentos nomeados. Este pode ser NULL se não existirem argumentos.
- nargsf é o número de argumentos posicionais somado á possível
Sinalizador
PY_VECTORCALL_ARGUMENTS_OFFSET. Para obter o número real de argumentos posicionais de nargsf, usePyVectorcall_NARGS().
- kwnames é uma tupla contendo os nomes dos argumentos nomeados;
em outras palavras, as chaves do dicionário kwargs. Estes nomes devem ser strings (instâncias de
strou uma subclasse) e eles devem ser únicos. Se não existem argumentos nomeados, então kwnames deve então ser NULL.
-
PY_VECTORCALL_ARGUMENTS_OFFSET¶ Se esse sinalizador é definido em um argumento nargsf do vectorcall, deve ser permitido ao chamado temporariamente mudar
args[-1]. Em outras palavras, args aponta para o argumento 1 (não 0) no vetor alocado. O chamado deve restaurar o valor deargs[-1]antes de retornar.Para
PyObject_VectorcallMethod(), este sinalizador significa queargs[0]pode ser alterado.Sempre que podem realizar a um custo tão baixo (sem alocações adicionais), invocadores são encorajados a usar
PY_VECTORCALL_ARGUMENTS_OFFSET. Isso permitirá invocados como métodos vinculados a instâncias fazerem suas próprias invocações (o que inclui um argumento self) muito eficientemente.
Para invocar um objeto que implementa vectorcall, utilize a função call API como qualquer outra invocável. PyObject_Vectorcall() será normalmente mais eficiente.
Nota
No CPython 3.8, a API vectorcall e funções relacionadas estavam disponíveis provisoriamente sob nomes com um sublinhado inicial: _PyObject_Vectorcall, _Py_TPFLAGS_HAVE_VECTORCALL, _PyObject_VectorcallMethod, _PyVectorcall_Function, _PyObject_CallOneArg, _PyObject_CallMethodNoArgs, _PyObject_CallMethodOneArg. Além disso, PyObject_VectorcallDict estava disponível como _PyObject_FastCallDict. Os nomes antigos ainda estão definidos como apelidos para os novos nomes sem o sublinhado.
Controle de recursão¶
Quando utilizando tp_call, invocadores não precisam se preocupar sobre recursão: CPython usa Py_EnterRecursiveCall() e Py_LeaveRecursiveCall() para chamadas utilizando tp_call.
Por questão de eficiência, este não é o caso de chamadas utilizando o vectorcall: o que chama deve utilizar Py_EnterRecursiveCall e Py_LeaveRecursiveCall se necessário.
API de suporte à chamada de vetores¶
-
Py_ssize_t
PyVectorcall_NARGS(size_t nargsf)¶ Dado um argumento de chamada de vetor nargsf, retorna o número real de argumentos. Atualmente equivalente a:
(Py_ssize_t)(nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET)
Entretanto, a função
PyVectorcall_NARGSdeve ser usada para permitir para futuras extensões.Novo na versão 3.8.
-
vectorcallfunc
PyVectorcall_Function(PyObject *op)¶ Se op não suporta o protocolo de chamada de vetor (seja porque o tipo ou a instância específica não suportam), retorne NULL. Se não, retorne o ponteiro da função chamada de vetor armazenado em op. Esta função nunca levanta uma exceção.
É mais útil checar se op suporta ou não chamada de vetor, o que pode ser feito checando
PyVectorcall_Function(op) != NULL.Novo na versão 3.8.
-
PyObject *
PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *dict)¶ Chama o
vectorcallfuncde callable com argumentos posicionais e nomeados dados em uma tupla e dicionário, respectivamente.Esta é uma função especializada, feita para ser colocada no slot
tp_callou usada em uma implementação detp_call. Ela não checa a flagPy_TPFLAGS_HAVE_VECTORCALLe não retorna paratp_call.Novo na versão 3.8.
API de chamada de objetos¶
Várias funções estão disponíveis para chamar um objeto Python. Cada uma converte seus argumentos para uma convenção suportada pelo objeto chamado – seja tp_call ou chamada de vetor. Para fazer o mínimo possível de conversões, escolha um que melhor se adapte ao formato de dados que você tem disponível.
A tabela a seguir resume as funções disponíveis; por favor, veja a documentação individual para detalhes.
Função |
chamável |
args |
kwargs |
|---|---|---|---|
|
tupla |
dict/ |
|
|
— |
— |
|
|
1 objeto |
— |
|
|
tupla/ |
— |
|
|
format |
— |
|
obj + |
format |
— |
|
|
variádica |
— |
|
obj + nome |
variádica |
— |
|
obj + nome |
— |
— |
|
obj + nome |
1 objeto |
— |
|
|
vectorcall |
vectorcall |
|
|
vectorcall |
dict/ |
|
arg + nome |
vectorcall |
vectorcall |
-
PyObject *
PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs)¶ - Retorna valor: Nova referência. Part of the Stable ABI.
Chama um objeto Python chamável de callable, com argumentos dados pela tupla args, e argumentos nomeados dados pelo dicionário kwargs.
args não deve ser NULL; use uma tupla vazia se não precisar de argumentos. Se nenhum argumento nomeado é necessário, kwargs pode ser NULL.
Retorna o resultado da chamada em sucesso, ou levanta uma exceção e retorna NULL em caso de falha.
Esse é o equivalente da expressão Python:
callable(*args, **kwargs).
-
PyObject *
PyObject_CallNoArgs(PyObject *callable)¶ - Part of the Stable ABI since version 3.10.
Chama um objeto Python chamável de callable sem nenhum argumento. É o jeito mais eficiente de chamar um objeto Python sem nenhum argumento.
Retorna o resultado da chamada em sucesso, ou levanta uma exceção e retorna NULL em caso de falha.
Novo na versão 3.9.
-
PyObject *
PyObject_CallOneArg(PyObject *callable, PyObject *arg)¶ Chama um objeto Python chamável de callable com exatamente 1 argumento posicional arg e nenhum argumento nomeado.
Retorna o resultado da chamada em sucesso, ou levanta uma exceção e retorna NULL em caso de falha.
Novo na versão 3.9.
-
PyObject *
PyObject_CallObject(PyObject *callable, PyObject *args)¶ - Retorna valor: Nova referência. Part of the Stable ABI.
Chama um objeto Python chamável de callable com argumentos dados pela tupla args. Se nenhum argumento é necessário, args pode ser NULL.
Retorna o resultado da chamada em sucesso, ou levanta uma exceção e retorna NULL em caso de falha.
Este é o equivalente da expressão Python:
callable(*args).
-
PyObject *
PyObject_CallFunction(PyObject *callable, const char *format, ...)¶ - Retorna valor: Nova referência. Part of the Stable ABI.
Chama um objeto Python chamável de callable, com um número variável de argumentos C. Os argumentos C são descritos usando uma string de estilo no formato
Py_BuildValue(). O formato pode ser NULL, indicando que nenhum argumento foi provido.Retorna o resultado da chamada em sucesso, ou levanta uma exceção e retorna NULL em caso de falha.
Este é o equivalente da expressão Python:
callable(*args).Note que se você apenas passa argumentos
PyObject*,PyObject_CallFunctionObjArgs()é uma alternativa mais rápida.Alterado na versão 3.4: O tipo de format foi mudado de
char *.
-
PyObject *
PyObject_CallMethod(PyObject *obj, const char *name, const char *format, ...)¶ - Retorna valor: Nova referência. Part of the Stable ABI.
Chama o método chamado name do objeto obj com um número variável de argumentos C. Os argumentos C são descritos com uma string de formato
Py_BuildValue()que deve produzir uma tupla.O formato pode ser NULL, indicado que nenhum argumento foi provido.
Retorna o resultado da chamada em sucesso, ou levanta uma exceção e retorna NULL em caso de falha.
Este é o equivalente da expressão Python:
obj.name(arg1, arg2, ...).Note que se você apenas passa argumentos
PyObject*,PyObject_CallMethodObjArgs()é uma alternativa mais rápida.Alterado na versão 3.4: Os tipos de name e format foram mudados de
char *.
-
PyObject *
PyObject_CallFunctionObjArgs(PyObject *callable, ...)¶ - Retorna valor: Nova referência. Part of the Stable ABI.
Chama um objeto Python chamável de callable, com um número variável de argumentos
PyObject*. Os argumentos são providos como um número variável de parâmetros seguidos por um NULL.Retorna o resultado da chamada em sucesso, ou levanta uma exceção e retorna NULL em caso de falha.
Este é o equivalente da expressão Python:
callable(arg1, arg2, ...).
-
PyObject *
PyObject_CallMethodObjArgs(PyObject *obj, PyObject *name, ...)¶ - Retorna valor: Nova referência. Part of the Stable ABI.
Chama um método do objeto Python obj, onde o nome do método é dado como um objeto string Python em name. É chamado com um número variável de argumentos
PyObject*. Os argumentos são providos como um número variável de parâmetros seguidos por um NULL.Retorna o resultado da chamada em sucesso, ou levanta uma exceção e retorna NULL em caso de falha.
-
PyObject *
PyObject_CallMethodNoArgs(PyObject *obj, PyObject *name)¶ Chama um método do objeto Python obj sem argumentos, onde o nome do método é fornecido como um objeto string do Python em name.
Retorna o resultado da chamada em sucesso, ou levanta uma exceção e retorna NULL em caso de falha.
Novo na versão 3.9.
-
PyObject *
PyObject_CallMethodOneArg(PyObject *obj, PyObject *name, PyObject *arg)¶ Chama um método do objeto Python obj com um argumento posicional arg, onde o nome do método é fornecido como um objeto string do Python em name.
Retorna o resultado da chamada em sucesso, ou levanta uma exceção e retorna NULL em caso de falha.
Novo na versão 3.9.
-
PyObject *
PyObject_Vectorcall(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwnames)¶ Chama um objeto Python chamável callable. Os argumentos são os mesmos de
vectorcallfunc. Se callable tiver suporte a vectorcall, isso chamará diretamente a função vectorcall armazenada em callable.Retorna o resultado da chamada em sucesso, ou levanta uma exceção e retorna NULL em caso de falha.
Novo na versão 3.9.
-
PyObject *
PyObject_VectorcallDict(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwdict)¶ Chama callable com argumentos posicionais passados exatamente como no protocolo vectorcall, mas com argumentos nomeados passados como um dicionário kwdict. O array args contém apenas os argumentos posicionais.
Independentemente de qual protocolo é usado internamente, uma conversão de argumentos precisa ser feita. Portanto, esta função só deve ser usada se o chamador já tiver um dicionário pronto para usar para os argumentos nomeados, mas não uma tupla para os argumentos posicionais.
Novo na versão 3.9.
-
PyObject *
PyObject_VectorcallMethod(PyObject *name, PyObject *const *args, size_t nargsf, PyObject *kwnames)¶ Chama um método usando a convenção de chamada vectorcall. O nome do método é dado como uma string Python name. O objeto cujo método é chamado é args[0], e o array args começando em args[1] representa os argumentos da chamada. Deve haver pelo menos um argumento posicional. nargsf é o número de argumentos posicionais incluindo args[0], mais
PY_VECTORCALL_ARGUMENTS_OFFSETse o valor deargs[0]puder ser alterado temporariamente. Argumentos nomeados podem ser passados como emPyObject_Vectorcall().Se o objeto tem a feature
Py_TPFLAGS_METHOD_DESCRIPTOR, isso irá chamar o objeto de método não vinculado com o vetor args inteiro como argumentos.Retorna o resultado da chamada em sucesso, ou levanta uma exceção e retorna NULL em caso de falha.
Novo na versão 3.9.
API de suporte a chamadas¶
-
int
PyCallable_Check(PyObject *o)¶ - Part of the Stable ABI.
Determine se o objeto o é chamável. Devolva
1se o objeto é chamável e0caso contrário. Esta função sempre tem êxito.