HOWTO · Python
Chamar uma função a partir do nome da string em Python
Demonstra como chamar uma função a partir de um string em Python
Nesta página
Quando o nome de uma função chega como string, procure-o em um conjunto definido de funções permitidas e chame o objeto de função encontrado. Um dicionário costuma ser a opção mais clara para comandos ou outras ações escolhidas pelo usuário: ele deixa visíveis os nomes disponíveis e impede que uma entrada arbitrária selecione código não relacionado.
Use um dicionário para mapear nomes aprovados para funções
Defina as funções normalmente e, em seguida, associe as strings aceitas aos respectivos objetos de função. Procure o nome solicitado e verifique se o resultado pode ser chamado antes de invocá-lo. Este exemplo trata um nome desconhecido sem tentar fazer uma chamada:
A execução fornecida concluiu este exemplo autocontido com código de saída 0 e exibiu 8. Execute-o com:
O código e os rótulos ou saídas exibidos nesta seção permanecem em inglês.
def add(left, right):
return left + right
def multiply(left, right):
return left * right
functions = {"add": add, "multiply": multiply}
name = "add"
function = functions.get(name)
if callable(function):
print(function(5, 3))
else:
print(f"Unknown function: {name}")
8
O mapeamento funciona como uma lista de permissões: somente os nomes adicionados a functions podem ser selecionados. Use .get() quando a ausência de um nome for uma entrada esperada e decida como a aplicação deve informar ou tratar um nome desconhecido. Se as funções receberem argumentos diferentes, valide também os argumentos da operação selecionada; encontrar o nome com sucesso não garante que a assinatura da chamada esteja correta.
Use getattr() para obter um atributo de um objeto ou módulo
Use getattr(object, name, default) quando a string deve selecionar um atributo de um objeto ou módulo específico. O terceiro argumento fornece um valor quando esse atributo não existe. Em seguida, verifique se o valor pode ser chamado: um atributo existente pode conter dados, e não uma função.
A execução fornecida concluiu este exemplo com código de saída 0 e exibiu 8. Ele obtém um método de instância vinculado: o Python associa calculator ao método, portanto passe somente os argumentos restantes do método. Execute-o com:
O código e os rótulos ou saídas exibidos nesta seção permanecem em inglês.
class Calculator:
def add(self, left, right):
return left + right
calculator = Calculator()
name = "add"
operation = getattr(calculator, name, None)
if callable(operation):
print(operation(5, 3))
else:
print(f"No callable attribute named {name}")
8
O mesmo padrão funciona com um objeto de módulo, por exemplo, getattr(math, name, None) depois de importar math. Procurar um método de instância na própria instância retorna um método vinculado; procurá-lo na classe retorna a função não vinculada e exige a instância como argumento. Restrinja o objeto de origem e os nomes de atributos permitidos quando a string vier de fora do seu código.
Use globals() e locals() somente quando o namespace for intencional
globals() retorna o namespace global do módulo atual. Ele não retorna variáveis locais. A busca no namespace global pode ser útil quando as funções pertencem intencionalmente a esse módulo. A execução fornecida concluiu este exemplo com código de saída 0 e exibiu 8. Execute-o com:
O código e os rótulos ou saídas exibidos nesta seção permanecem em inglês.
def add(left, right):
return left + right
name = "add"
function = globals().get(name)
if callable(function):
print(function(5, 3))
else:
print(f"Unknown global function: {name}")
8
locals() refere-se ao namespace local no ponto em que é chamado. Dentro de uma função, ele pode expor os nomes locais a essa função; não inspeciona as variáveis locais de quem a chamou nem faz uma busca geral pelo programa. Seu comportamento depende do escopo, por isso costuma ser menos claro e menos adequado como mecanismo de despacho do que um mapeamento explícito. Para saber mais sobre dicionários, consulte o tutorial de dicionários do Python.
Por que eval() é arriscado para buscar funções
eval() avalia uma expressão Python, em vez de procurar somente um nome de função aprovado. Por exemplo, eval("add(5, 3)") analisa e avalia uma expressão de chamada usando os nomes disponíveis no ambiente de avaliação. Se a expressão contiver uma entrada não confiável, avaliá-la poderá executar código com os privilégios do processo Python. Não use eval() para despachar nomes fornecidos por usuários, arquivos, solicitações de rede ou outras fontes não confiáveis.
Se uma expressão realmente vier de uma fonte confiável e controlada, a documentação do Python explica o comportamento e os parâmetros de namespace de eval(). Para a seleção comum de funções, uma lista de permissões em um dicionário é mais simples e limita as opções da entrada. Analisar ou validar o texto não torna a avaliação arbitrária um substituto seguro para um conjunto explícito de operações.
Escolha o método de busca adequado à sua entrada
Use um dicionário quando as ações disponíveis precisarem ser explícitas, especialmente para nomes fornecidos pelo usuário ou vindos de fontes externas. Use getattr() quando o objeto ou módulo já estiver definido e a string servir para selecionar um de seus atributos; verifique o valor padrão e se o resultado pode ser chamado, e considere a vinculação de métodos. Use globals() somente quando a busca no nível do módulo for intencional. Use locals() somente quando o código precisar deliberadamente dos nomes do escopo local atual, e não como um mecanismo geral de despacho. Evite eval() para buscar nomes quando a entrada não for totalmente confiável.
Em todos os casos, buscar e invocar são decisões distintas: primeiro restrinja quais objetos chamáveis podem ser selecionados; depois passe argumentos compatíveis com a interface deles. Para um conjunto fixo de comandos, essa separação facilita a auditoria e a manutenção do comportamento.