2009-05-11 10 views
101

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.Comment puis-je trouver le nombre d'arguments d'une fonction Python?

Exemple:

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

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

+2

Je suis en train de mettre en place un système de notification, qui ne sait pas vraiment à l'avance combien d'arguments le récepteur veut. (Normalement c'est tous ou aucun.) –

+39

la question est entièrement justifiée; si ce n'était pas le cas (puisque vous pouvez toujours lire la source), il n'y aurait aucune justification pour le module de bibliothèque standard 'inspect'. – flow

+0

De nombreuses langues implémentent au moins une fonctionnalité injustifiée. Le module 'inspect' a beaucoup d'autres fonctionnalités, il est donc injuste de dire que tout le module serait injustifié si une fonction particulière était. De plus, il est facile de voir comment cette fonctionnalité pourrait être mal utilisée. (Voir http://stackoverflow.com/questions/741950). Cela dit, c'est une fonctionnalité utile, en particulier pour l'écriture de décorateurs et d'autres fonctions qui fonctionnent sur la fonction. – user1612868

Répondre

43

La réponse précédemment acceptée a été deprecated au Python 3.0. Au lieu d'utiliser inspect.getargspec, vous devriez maintenant opter pour la classe Signature qui l'a remplacée.

Création d'une signature pour la fonction est facile via le signature function:

from inspect import signature 

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

sig = signature(someMethod) 

Maintenant, vous pouvez voir ses paramètres rapidement en str ing il:

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

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

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

De plus, vous pouvez appeler len sur sig.parameters pour voir aussi le nombre d'arguments de cette fonction nécessite:

print(len(params)) # 3 

Chaque entrée dans le mappage params est en fait un Parameter object qui a d'autres attributs rendant votre vie Plus facile. Par exemple, saisir un paramètre et l'affichage de sa valeur par défaut est maintenant facile à réaliser avec:

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

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


Comme pour les utilisateurs Python 2.x, tandis que inspect.getargspecn'est pas dépréciée, la langue sera bientôt :-). La classe Signature n'est pas disponible dans la série 2.x et ne le sera pas. Donc, vous devez 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 getargspec en Python 2 et le passage à signature dans 3 est trop difficile, vous avez la possibilité d'utiliser de valeurinspect.getfullargspec. Il offre une interface similaire à getargspec (un seul argument appelable) afin de saisir les arguments d'une fonction lors de la manipulation aussi quelques cas supplémentaires getargspec ne possède pas:

from inspect import getfullargspec 

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

args = getfullargspec(someMethod) 

Comme getargspec, getfullargspec renvoie une NamedTuple qui contient les arguments.

print(args) 
FullArgSpec(args=['self', 'arg1', 'kwarg1'], varargs=None, varkw=None, defaults=(None,), kwonlyargs=[], kwonlydefaults=None, annotations={}) 
+1

Merci d'avoir écrit une nouvelle réponse à une question aussi ancienne, c'est génial! –

+0

Vous êtes les bienvenus @ GeorgSchölly. J'ai été surpris qu'une question populaire comme celle-ci proposait des solutions qui étaient soit obsolètes soit en bas sournoises (voir dans l'attribut 'co_argcount') –

+0

' getfullargspec' n'est pas implémenté dans Python 2.x, vous devez utiliser 'getargspec' –

114
import inspect 
inspect.getargspec(someMethod) 

voir the inspect module

+4

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 builtins est d'analyser leur chaîne __doc__, ce qui est fugace mais faisable. – Cerin

+3

Ceci est obsolète dans Python 3: https://docs.python.org/3/library/inspect.html#inspect.getargspec – noisecapella

+0

Existe-t-il une solution qui ne soit pas déconseillée dans Python 3? – hlin117

16

inspect.getargspec()

Get the names and default values of a function’s arguments. A tuple of four things is returned: (args, varargs, varkw, defaults). args is a list of the argument names (it may contain nested lists). varargs and varkw are the names of the * and ** arguments or None. defaults is a tuple of default argument values or None if there are no default arguments; if this tuple has n elements, they correspond to the last n elements listed in args.

Changed in version 2.6: Returns a named tuple ArgSpec(args, varargs, keywords, defaults).

Voir can-you-list-the-keyword-arguments-a-python-function-receives.

25
someMethod.func_code.co_argcount 

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

import sys 

sys._getframe().func_code.co_argcount 
+0

+1, d'où avez-vous eu cela? – elyase

+4

@elyase, faites simplement: 'dir (someMethod)' -> ''func_code''; Allez plus loin: 'dir (someMethod.func_code)' -> ''co_argcount''; Vous pouvez utiliser le 'dir()' intégré pour déterminer les méthodes disponibles d'un objet. –

+0

@elyase J'étais aussi courageux, donc j'ai trouvé ce https://docs.python.org/2/library/inspect.html#types-and-members – rodripf

3

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

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

help(<method>) 

donne le 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 
+0

Il serait bon pour les gens de laisser un commentaire sur ce qui ne va pas avec un post que de simplement cliquer sur le bouton moins. –

+2

La fonction 'help' ne montre que ce que dit la docstring. Avez-vous même testé si cela fonctionne avec la définition de la fonction dans la question? – 0xc0de

+0

@ 0xc0de - L'avez vous testé? Parce que ça fonctionne vraiment. 'help()' crache plus que la docstring - même sur un 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 n'était pas claire quant à savoir si elle avait besoin d'une réponse conviviale à la machine ou à l'humain. Si cela doit seulement être humain, 'help() 'est parfaitement adéquat. – ArtOfWarfare

1

Comme d'autres réponses suggèrent, getargspec fonctionne bien aussi longtemps que la chose requêtée est en fait une fonction. Il ne fonctionne pas pour intégrés des fonctions telles que open, len, etc, et jetteront une exception dans ce cas:

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

La fonction ci-dessous (inspirée par this answer) démontre une solution de contournement. Il retourne le nombre de args 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 la fonction de la chaîne __doc__. Évidemment, cela dépend du format de la chaîne, ce qui n'est pas très robuste!

Questions connexes