Como posso encontrar o número de argumentos de uma função Python?

163

Como posso encontrar o número de argumentos de uma função Python? Preciso saber quantos argumentos normais ele possui e quantos argumentos nomeados.

Exemplo:

def someMethod(self, arg1, kwarg1=None):
    pass

Este método possui 2 argumentos e 1 argumento nomeado.

Georg Schölly
fonte
43
a questão é totalmente justificada; se não fosse (como você sempre pode ler a fonte), não haveria justificativa para o inspectmódulo de biblioteca padrão.
flow
Muitas linguagens implementam pelo menos um recurso injustificado. O inspectmódulo possui muitos outros recursos, portanto, é injusto dizer que o módulo inteiro seria injustificado se uma função específica fosse. Além disso, é fácil ver como esse recurso pode ser mal utilizado. (Consulte stackoverflow.com/questions/741950 ). Dito isto, é um recurso útil, especialmente para escrever decoradores e outras funções que operam nessa função.
User1612868

Respostas:

130

A resposta aceita anteriormente foi descontinuada a partir de Python 3.0. Em vez de usar, inspect.getargspecvocê deve agora optar pela Signatureclasse que a substituiu.

Criar uma assinatura para a função é fácil através da signaturefunção :

from inspect import signature

def someMethod(self, arg1, kwarg1=None):
    pass

sig = signature(someMethod)

Agora, você pode visualizar seus parâmetros rapidamente, usando str-o:

str(sig)  # returns: '(self, arg1, kwarg1=None)'

ou você também pode obter um mapeamento de nomes de atributos para objetos de parâmetro via sig.parameters.

params = sig.parameters 
print(params['kwarg1']) # prints: kwarg1=20

Além disso, você pode chamar lende sig.parametersver também o número de argumentos Esta função exige:

print(len(params))  # 3

Cada entrada no paramsmapeamento é na verdade um Parameterobjeto que possui outros atributos, facilitando sua vida. Por exemplo, pegar um parâmetro e visualizar seu valor padrão agora é facilmente realizado com:

kwarg1 = params['kwarg1']
kwarg1.default # returns: None

da mesma forma para o restante dos objetos contidos em parameters.


Quanto aos 2.xusuários de Python , embora inspect.getargspec não seja preterido, a linguagem em breve será :-). A Signatureturma não está disponível na 2.xsérie e não estará. Então você ainda precisa trabalhar inspect.getargspec.

Quanto à transição entre Python 2 e 3, se você tiver o código que se baseia na interface getargspecem Python 2 e mudar para signaturenos 3é muito difícil, você tem a opção valiosa de utilizar inspect.getfullargspec. Ele oferece uma interface semelhante a getargspec(um único argumento que pode ser chamado) para capturar os argumentos de uma função enquanto também lida com alguns casos adicionais que getargspecnão:

from inspect import getfullargspec

def someMethod(self, arg1, kwarg1=None):
    pass

args = getfullargspec(someMethod)

Assim como getargspec, getfullargspecretorna a NamedTupleque contém os argumentos.

print(args)
FullArgSpec(args=['self', 'arg1', 'kwarg1'], varargs=None, varkw=None, defaults=(None,), kwonlyargs=[], kwonlydefaults=None, annotations={})
Dimitris Fasarakis Hilliard
fonte
1
De nada @ GeorgSchölly. Fiquei surpreso que uma pergunta popular como esta oferecesse soluções que foram preteridas ou que foram co_argcount
furtivas
1
getfullargspecnão é implementado em Python 2.x, você precisará usargetargspec
Peter Gibson
getargspecnão funciona em built-in funções: getargspec(open)TypeError: <built-in function open> is not a Python functionVeja esta resposta para algumas idéias ...
starfry
No seu último exemplo, quando você o print(args)recebe, defaults=(None,)você não recebe defaults=None.
Seanny123
si existe uma maneira de obter a contagem de parâmetros original para uma função que foi decorada após a decoração ..?
Gulats 6/08/19
117
import inspect
inspect.getargspec(someMethod)

veja o módulo de inspeção

Jochen Ritzel
fonte
5
Geralmente o que você deseja, mas isso não funciona para funções internas. A única maneira de saber como obter essas informações para os componentes internos é analisar sua sequência de documentos , que é imprecisa, mas factível.
Cerin
5
Este é obsoleto em Python 3: docs.python.org/3/library/inspect.html#inspect.getargspec
noisecapella
Existe uma solução que não foi preterida no Python 3?
Hlin117 27/05
1
Se você seguir o link, verá que ele recomenda o uso de inspect.signature- docs.python.org/3/library/inspect.html#inspect.signature
coderforlife
Postei outra abordagem possível para funções internas sem analisar a documentação aqui: stackoverflow.com/questions/48567935/…
HelloWorld
31
someMethod.func_code.co_argcount

ou, se o nome da função atual for indeterminado:

import sys

sys._getframe().func_code.co_argcount
miaoever
fonte
4
@elyase, basta fazer: dir(someMethod)-> 'func_code'; Vá além: dir(someMethod.func_code)-> 'co_argcount'; Você pode usar o built-in dir()para determinar os métodos disponíveis de um objeto.
@elyase eu estava courious também, então eu encontrei este docs.python.org/2/library/inspect.html#types-and-members
rodripf
Para suportar Python 3:six.get_function_code(someMethod).co_argcount
noisecapella
8
@noisecapella há necessidade de um terceiro módulo partido, quando você pode simplesmente fazersome_method.__code__.co_argcount
Vallentin
1
Em geral, você não deve espiar dentro do objeto de função para observar essas coisas. co_argcounté usado internamente durante a avaliação do objeto de código. O que estou tentando dizer é que realmente não há garantias de que esses atributos não mudem de uma versão para outra.
Dimitris Fasarakis Hilliard
16

inspect.getargspec ()

Obtenha os nomes e os valores padrão dos argumentos de uma função. Uma tupla de quatro coisas é retornada: (args, varargs, varkw, padrões). args é uma lista dos nomes dos argumentos (pode conter listas aninhadas). varargs e varkw são os nomes dos argumentos * e ** ou Nenhum. defaults é uma tupla de valores de argumento padrão ou None se não houver argumentos padrão; se essa tupla tiver n elementos, eles corresponderão aos últimos n elementos listados em args.

Alterado na versão 2.6: Retorna uma tupla nomeada ArgSpec (args, varargs, palavras-chave, padrões).

Veja você pode listar a palavra-chave-argumentos-a-função-python-recebe .

gimel
fonte
5

Além disso, também vi que na maioria das vezes a função help () realmente ajuda

Por exemplo, fornece todos os detalhes sobre os argumentos necessários.

help(<method>)

dá o abaixo

method(self, **kwargs) method of apiclient.discovery.Resource instance
Retrieves a report which is a collection of properties / statistics for a specific customer.

Args:
  date: string, Represents the date in yyyy-mm-dd format for which the data is to be fetched. (required)
  pageToken: string, Token to specify next page.
  parameters: string, Represents the application name, parameter name pairs to fetch in csv as app_name1:param_name1, app_name2:param_name2.

Returns:
  An object of the form:

    { # JSON template for a collection of usage reports.
    "nextPageToken": "A String", # Token for retrieving the next page
    "kind": "admin#reports#usageReports", # Th
Venu Murthy
fonte
Seria bom que as pessoas deixassem um comentário sobre o que há de errado com uma postagem do que simplesmente clicar no botão de menos.
Venu Murthy
2
helpA função mostra apenas o que a doutrina diz. Você já testou se funciona com a definição de função na pergunta?
0xc0de 02/11/2014
@ 0xc0de - Você já testou? Porque realmente funciona. help()cospe mais do que apenas a sequência de documentos - mesmo em código não documentado, ele ainda imprime o argspec e informa onde o código foi definido. A pessoa que postou a pergunta original não sabia ao certo se precisava de uma resposta amigável à máquina ou ao ser humano. Se ele só precisa ser humano, help()é perfeitamente adequado.
ArtOfWarfare 17/01
@ArtOfWarfare de forma alguma, pois agora você teria que analisar o que quer que help()retorne e tentar encontrar o argse kwargs.
Vallentin
5

Boas notícias para quem deseja fazer isso de maneira portátil entre o Python 2 e o Python 3.6+: use inspect.getfullargspec()method. Funciona no Python 2.xe 3.6+

Como Jim Fasarakis Hilliard e outros apontaram, costumava ser assim:
1. No Python 2.x: use inspect.getargspec()
2. No Python 3.x: use assinatura, como getargspec()e getfullargspec()foi preterido.

No entanto, iniciando o Python 3.6 (por demanda popular?), As coisas mudaram para melhor:

Na página de documentação do Python 3 :

inspect.getfullargspec (func)

Alterado na versão 3.6 : esse método foi documentado anteriormente como obsoleto no signature()Python 3.5, mas essa decisão foi revertida para restaurar uma interface padrão claramente suportada para código Python 2/3 de fonte única que migra para longe da getargspec()API herdada .

HAltos
fonte
3

inspect.getargspec () para atender às suas necessidades

from inspect import getargspec

def func(a, b):
    pass
print len(getargspec(func).args)
Eds_k
fonte
1
Bem-vindo ao Stack Overflow! Por favor, não responda apenas com o código fonte. Tente fornecer uma boa descrição sobre como sua solução funciona. Veja: Como escrevo uma boa resposta? . Obrigado
quinta-feira 30/09/18
2

Como sugerem outras respostas, getargspecfunciona bem desde que a coisa que está sendo consultada seja realmente uma função. Ele não funciona para built-in funções, tais como open, len, etc, e irá lançar uma exceção em tais casos:

TypeError: <built-in function open> is not a Python function

A função abaixo (inspirada nesta resposta ) demonstra uma solução alternativa. Retorna o número de argumentos esperado por f:

from inspect import isfunction, getargspec
def num_args(f):
  if isfunction(f):
    return len(getargspec(f).args)
  else:
    spec = f.__doc__.split('\n')[0]
    args = spec[spec.find('(')+1:spec.find(')')]
    return args.count(',')+1 if args else 0

A idéia é analisar a especificação da função fora da __doc__string. Obviamente, isso depende do formato da referida string, portanto, dificilmente é robusta!

starfry
fonte
2

func.__code__.co_argcountdá-lhe número de quaisquer argumentos ANTES *args

func.__kwdefaults__fornece um ditado dos argumentos da palavra - chave APÓS *args

func.__code__.co_kwonlyargcount é igual a len(func.__kwdefaults__)

func.__defaults__fornece os valores dos argumentos opcionais que aparecem antes *args

Aqui está a ilustração simples:

a ilustração

>>> def a(b, c, d, e, f=1, g=3, h=None, *i, j=2, k=3, **L):
    pass

>>> a.__code__.co_argcount
7
>>> a.__defaults__
(1, 3, None)
>>> len(a.__defaults__)
3
>>> 
>>> 
>>> a.__kwdefaults__
{'j': 2, 'k': 3}
>>> len(a.__kwdefaults__)
2
>>> a.__code__.co_kwonlyargcount
2
Hzzkygcs
fonte
0

No:

import inspect 

class X:
    def xyz(self, a, b, c): 
        return 

print(len(inspect.getfullargspec(X.xyz).args))

Fora:

4


Nota: Se xyz não pertencesse à classe X e não tivesse "eu" e apenas "a, b, c", seria impresso 3.

Para python abaixo de 3,5, convém substituir inspect.getfullargspecpor inspect.getargspecno código acima.

Guillaume Chevalier
fonte