Dada a função Python:
def a_method(arg1, arg2):
pass
Como posso extrair o número e os nomes dos argumentos. Ou seja, dado que tenho uma referência func
, quero func.[something]
que retorne("arg1", "arg2")
.
O cenário de uso para isso é que eu tenho um decorador e desejo usar os argumentos do método na mesma ordem em que aparecem para a função real como uma chave. Ou seja, como ficaria o decorador impresso "a,b"
quando eu ligo a_method("a", "b")
?
Respostas:
Dê uma olhada no
inspect
módulo - isso fará a inspeção das várias propriedades do objeto de código para você.Os outros resultados são o nome das variáveis * args e ** kwargs e os padrões fornecidos. ie
Observe que alguns callables podem não ser introspectáveis em certas implementações do Python. Por exemplo, no CPython, algumas funções internas definidas em C não fornecem metadados sobre seus argumentos. Como resultado, você receberá um
ValueError
se usarinspect.getfullargspec()
em uma função interna.Desde o Python 3.3, você pode usar
inspect.signature()
para ver a assinatura de chamada de um objeto que pode ser chamado:fonte
(4,)
correspondec
especificamente ao parâmetro keyword ?inspect.getargspec
está obsoleto , mas a substituição estáinspect.getfullargspec
.No CPython, o número de argumentos é
e seus nomes estão no início de
Esses são os detalhes da implementação do CPython, portanto, isso provavelmente não funciona em outras implementações do Python, como IronPython e Jython.
Uma maneira portátil de admitir argumentos de "passagem" é definir sua função com a assinatura
func(*args, **kwargs)
. Isso é muito usado, por exemplo , no matplotlib , onde a camada externa da API passa muitos argumentos de palavras-chave para a API de nível inferior.fonte
*args
def foo(x, *args, y, **kwargs): # foo.__code__.co_argcount == 1
Em um método decorador, você pode listar argumentos do método original desta maneira:
Se
**kwargs
são importantes para você, será um pouco complicado:Exemplo:
fonte
Acho que o que você está procurando é o método locals -
fonte
A versão do Python 3 é:
O método retorna um dicionário contendo args e kwargs.
fonte
[:fn.__code__.co_argcount]
é muito importante se você estiver procurando pelos argumentos da função - caso contrário, também inclui nomes criados dentro da função.Aqui está algo que acho que funcionará para o que você deseja, usando um decorador.
Execute-o, ele produzirá a seguinte saída:
fonte
Python 3.5 ou superior:
Então anteriormente:
Agora:
Testar:
Dado que temos a função 'function' que recebe o argumento 'arg', isso será avaliado como True, caso contrário, como False.
Exemplo do console do Python:
fonte
No Python 3. + com o
Signature
objeto em mãos, uma maneira fácil de obter um mapeamento entre nomes de argumentos e valores, é usando obind()
método Signature !Por exemplo, aqui está um decorador para imprimir um mapa como esse:
fonte
Aqui está outra maneira de obter os parâmetros de função sem usar nenhum módulo.
Resultado:
fonte
Retorna uma lista de nomes de argumentos, cuida de parciais e funções regulares:
fonte
Atualização para a resposta de Brian :
Se uma função no Python 3 tiver argumentos apenas de palavras-chave, será necessário usar
inspect.getfullargspec
:gera isso:
fonte
No python 3, abaixo, é para fazer
*args
e**kwargs
entrar em umdict
(useOrderedDict
para python <3.6 para manterdict
ordens):fonte
inspect.signature
é muito lento. A maneira mais rápida éfonte
Para atualizar um pouco a resposta de Brian , há agora uma boa backport de
inspect.signature
que você pode usar em versões mais antigas do Python:funcsigs
. Então, minha preferência pessoal iria paraPor diversão, se você estiver interessado em brincar com
Signature
objetos e até criar funções com assinaturas aleatórias dinamicamente, poderá dar uma olhada no meumakefun
projeto.fonte
E sobre
dir()
evars()
agora?Parece fazer exatamente o que está sendo pedido, super simples…
Deve ser chamado de dentro do escopo da função.
Mas tenha cuidado para que ele retorne todas as variáveis locais; portanto, faça isso no início da função, se necessário.
Observe também que, conforme apontado nos comentários, isso não permite que seja feito fora do escopo. Portanto, não é exatamente o cenário do OP, mas ainda corresponde ao título da pergunta. Daí a minha resposta.
fonte