Comment puis-je trouver le nombre d'arguments d'une fonction Python?

163

Comment puis-je trouver le nombre d'arguments d'une fonction Python? J'ai besoin de savoir combien d'arguments normaux il a et combien d'arguments nommés.

Exemple:

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

Cette méthode a 2 arguments et 1 argument nommé.

Georg Schölly
la source
43
la question est pleinement justifiée; si ce n'était pas le cas (puisque vous pouvez toujours lire la source), il n'y aurait aucune justification pour le inspectmodule de bibliothèque standard.
écoulement
De nombreux langages implémentent au moins une fonctionnalité injustifiée. Le inspectmodule a beaucoup d'autres fonctionnalités, il est donc injuste de dire que l'ensemble du module serait injustifié si une fonction particulière y figurait. De plus, il est facile de voir comment cette fonctionnalité pourrait être mal utilisée. (Voir stackoverflow.com/questions/741950 ). Cela dit, c'est une fonctionnalité utile, en particulier pour écrire des décorateurs et d'autres fonctions qui fonctionnent sur la fonction.
user1612868

Réponses:

131

La réponse précédemment acceptée a été dépréciée au Python 3.0. Au lieu d'utiliser, inspect.getargspecvous devriez maintenant opter pour la Signatureclasse qui l'a remplacé.

Créer une signature pour la fonction est facile via la signaturefonction :

from inspect import signature

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

sig = signature(someMethod)

Désormais, vous pouvez soit afficher rapidement ses paramètres en l' strutilisant:

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

ou vous pouvez également obtenir un mappage des noms d'attributs aux objets paramètres via sig.parameters.

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

De plus, vous pouvez appeler lenle sig.parametersvoir aussi le nombre d'arguments de cette fonction nécessite:

print(len(params))  # 3

Chaque entrée du paramsmappage est en fait un Parameterobjet qui a d'autres attributs qui vous facilitent la vie. Par exemple, saisir un paramètre et afficher sa valeur par défaut est désormais facile avec:

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

de même pour le reste des objets contenus dans parameters.


Quant aux 2.xutilisateurs de Python , bien que inspect.getargspec non obsolète, le langage le sera bientôt :-). La Signatureclasse n'est pas disponible dans la 2.xsérie et ne le sera pas. Vous devez donc toujours travailler avec inspect.getargspec.

En ce qui concerne la transition entre Python 2 et 3, si vous avez du code qui repose sur l'interface de getargspecPython 2 et que le passage à signaturedans 3est trop difficile, vous avez la possibilité d'utiliser inspect.getfullargspec. Il offre une interface similaire à getargspec(un seul argument appelable) afin de récupérer les arguments d'une fonction tout en gérant des cas supplémentaires qui getargspecne le font pas:

from inspect import getfullargspec

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

args = getfullargspec(someMethod)

Comme avec getargspec, getfullargspecrenvoie a NamedTuplequi contient les arguments.

print(args)
FullArgSpec(args=['self', 'arg1', 'kwarg1'], varargs=None, varkw=None, defaults=(None,), kwonlyargs=[], kwonlydefaults=None, annotations={})
Dimitris Fasarakis Hilliard
la source
1
De rien, @ GeorgSchölly. J'ai été surpris qu'une question populaire comme celle-ci proposait des solutions qui étaient soit obsolètes, soit sournoises ( co_argcount
jetant un coup d'œil
1
getfullargspecn'est pas implémenté dans Python 2.x, vous devez utilisergetargspec
Peter Gibson
getargspecne fonctionne pas sur les fonctions intégrées: getargspec(open)donne TypeError: <built-in function open> is not a Python functionVoir cette réponse pour quelques idées ...
starfry
Dans votre dernier exemple, lorsque vous faites print(args)vous ne recevez pas que defaults=(None,)vous obtenez defaults=None.
Seanny123
s'il existe un moyen d'obtenir le nombre de paramètres d'origine pour une fonction qui a été décorée après la décoration ..?
Gulats
117
import inspect
inspect.getargspec(someMethod)

voir le module inspect

Jochen Ritzel
la source
5
Généralement ce que vous voulez, mais cela ne fonctionne pas pour les fonctions intégrées. La seule façon de savoir pour obtenir ces informations pour les builtins est d'analyser leur doc string, ce qui est fugace mais faisable.
Cerin le
5
Ceci est obsolète dans Python 3: docs.python.org/3/library/inspect.html#inspect.getargspec
noisecapella
Existe-t-il une solution qui n'est pas obsolète dans Python 3?
hlin117
1
Si vous suivez le lien, vous verrez qu'il recommande d'utiliser inspect.signature- docs.python.org/3/library/inspect.html#inspect.signature
coderforlife
J'ai posté une autre approche possible pour les fonctions intégrées sans analyser la docstring ici: stackoverflow.com/questions/48567935/...
HelloWorld
31
someMethod.func_code.co_argcount

ou, si le nom de la fonction actuelle est indéterminé:

import sys

sys._getframe().func_code.co_argcount
miaoever
la source
4
@elyase, faites simplement: dir(someMethod)-> 'func_code'; Allez plus loin: dir(someMethod.func_code)-> 'co_argcount'; Vous pouvez utiliser la fonction intégrée dir()pour déterminer les méthodes disponibles d'un objet.
@elyase J'étais aussi courtois, alors j'ai trouvé ce docs.python.org/2/library/inspect.html#types-and-members
rodripf
Pour prendre en charge Python 3:six.get_function_code(someMethod).co_argcount
noisecapella
8
@noisecapella pas besoin d'un module tiers, quand vous pouvez le faire simplementsome_method.__code__.co_argcount
vallentin
1
En général, vous ne devriez pas jeter un œil à l'intérieur de l'objet de fonction pour regarder ces choses. co_argcountest utilisé en interne lors de l'évaluation de l'objet code. Ce que j'essaie de dire, c'est qu'il n'y a vraiment aucune garantie que ces attributs ne changeront pas d'une version à l'autre.
Dimitris Fasarakis Hilliard
16

inspect.getargspec ()

Obtenez les noms et les valeurs par défaut des arguments d'une fonction. Un tuple de quatre choses est retourné: (args, varargs, varkw, defaults). args est une liste des noms d'arguments (il peut contenir des listes imbriquées). varargs et varkw sont les noms des arguments * et ** ou None. defaults est un tuple de valeurs d'argument par défaut ou None s'il n'y a pas d'arguments par défaut; si ce tuple a n éléments, ils correspondent aux n derniers éléments listés dans args.

Modifié dans la version 2.6: renvoie un tuple nommé ArgSpec (args, varargs, mots-clés, valeurs par défaut).

Voir pouvez-vous-lister-les-arguments-mot-clé-qu'une-fonction-python-reçoit .

gimel
la source
5

Ajoutant à ce qui précède, j'ai également vu que la plupart du temps, la fonction help () aide vraiment

Par exemple, il donne tous les détails sur les arguments qu'il prend.

help(<method>)

donne le ci-dessous

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
la source
Il serait bon pour les gens de laisser un commentaire sur ce qui ne va pas avec un message plutôt que de simplement cliquer sur le bouton moins.
Venu Murthy
2
helpLa fonction ne montre que ce que dit la docstring. Avez-vous même testé si cela fonctionne avec la définition de fonction dans la question?
0xc0de
@ 0xc0de - L'avez-vous testé? Parce que ça marche vraiment. help()crache plus que la simple docstring - même sur du code non documenté, il imprime toujours l'argspec et vous indique où le code a été défini. La personne qui a posté la question initiale ne savait pas si elle avait besoin d'une réponse qui soit adaptée à la machine ou à l'homme. S'il a seulement besoin d'être humain, help()c'est parfaitement adéquat.
ArtOfWarfare
@ArtOfWarfare pas du tout, car maintenant vous devriez analyser tout ce qui help()retourne et essayer de trouver le argset kwargs.
vallentin
5

Bonne nouvelle pour les personnes qui souhaitent le faire de manière portable entre Python 2 et Python 3.6+: utilisez la inspect.getfullargspec()méthode. Cela fonctionne à la fois dans Python 2.x et 3.6+

Comme Jim Fasarakis Hilliard et d'autres l'ont souligné, c'était comme ceci:
1. En Python 2.x: utiliser inspect.getargspec()
2. En Python 3.x: utiliser la signature, comme getargspec()et getfullargspec()étaient obsolètes.

Cependant, à partir de Python 3.6 (à la demande générale?), Les choses ont changé pour mieux:

Depuis la page de documentation de Python 3 :

inspect.getfullargspec (func)

Modifié dans la version 3.6 : Cette méthode était précédemment documentée comme obsolète au profit de signature()Python 3.5, mais cette décision a été annulée afin de restaurer une interface standard clairement prise en charge pour le code Python 2/3 à source unique migrant hors de l'ancienne getargspec()API.

HAltos
la source
3

inspect.getargspec () pour répondre à vos besoins

from inspect import getargspec

def func(a, b):
    pass
print len(getargspec(func).args)
Eds_k
la source
1
Bienvenue dans Stack Overflow! Veuillez ne pas répondre uniquement avec le code source. Essayez de fournir une belle description du fonctionnement de votre solution. Voir: Comment écrire une bonne réponse? . Merci
sɐunıɔ ןɐ qɐp
2

Comme d'autres réponses le suggèrent, getargspecfonctionne bien tant que l'objet interrogé est en fait une fonction. Il ne fonctionne pas pour intégré des fonctions telles que open, len, etc, et va lancer une exception dans ce cas:

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

La fonction ci-dessous (inspirée par cette réponse ) montre une solution de contournement. Il renvoie le nombre d'arguments attendus par 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

L'idée est d'analyser la spécification de fonction hors de la __doc__chaîne. Évidemment, cela dépend du format de ladite chaîne, donc ce n'est guère robuste!

starfry
la source
2

func.__code__.co_argcountvous donne plusieurs des arguments AVANT *args

func.__kwdefaults__vous donne un dict des arguments de mot - clé APRÈS *args

func.__code__.co_kwonlyargcount est égal à len(func.__kwdefaults__)

func.__defaults__vous donne les valeurs des arguments facultatifs qui apparaissent avant *args

Voici l'illustration simple:

l'illustration

>>> 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
la source
0

Dans:

import inspect 

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

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

En dehors:

4


Remarque: si xyz n'était pas dans la classe X et n'avait pas de "self" et juste "a, b, c", alors il aurait imprimé 3.

Pour python inférieur à 3.5, vous voudrez peut-être remplacer inspect.getfullargspecpar inspect.getargspecdans le code ci-dessus.

Guillaume Chevalier
la source