282 votes

Comment obtenir les noms des paramètres des méthodes ?

Étant donné la fonction Python :

def a_method(arg1, arg2):
    pass

Comment puis-je extraire le nombre et les noms des arguments. C'est-à-dire que, étant donné que j'ai une référence à func Je veux le func.[something] pour revenir ("arg1", "arg2") .

Le scénario d'utilisation est le suivant : j'ai un décorateur et je souhaite utiliser les arguments de la méthode dans le même ordre qu'ils apparaissent pour la fonction réelle en tant que clé. Par exemple, comment le décorateur pourrait-il ressembler à l'impression suivante "a,b" quand j'appelle a_method("a", "b") ?

1 votes

Pour une liste différente de réponses à une question presque identique, voir cet autre post de stackoverflow

4 votes

Votre titre est trompeur : quand on dit 'méthode' par rapport au mot 'fonction', on pense généralement à une méthode de classe. Pour la fonction, votre réponse sélectionnée (de Jouni K. Seppanen) est bonne. Mais pour la méthode (de classe), elle ne fonctionne pas et la solution de l'inspecteur (de Brian) devrait être utilisée.

411voto

Brian Points 48423

Jetez un coup d'œil à la inspect qui se chargera d'inspecter les différentes propriétés des objets du code pour vous.

>>> inspect.getfullargspec(a_method)
(['arg1', 'arg2'], None, None, None)

Les autres résultats sont le nom des variables *args et **kwargs, et les valeurs par défaut fournies. ie.

>>> def foo(a, b, c=4, *arglist, **keywords): pass
>>> inspect.getfullargspec(foo)
(['a', 'b', 'c'], 'arglist', 'keywords', (4,))

Notez que certains callables peuvent ne pas être introspectables dans certaines implémentations de Python. Par exemple, dans CPython, certaines fonctions intégrées définies en C ne fournissent aucune métadonnée sur leurs arguments. Par conséquent, vous obtiendrez un ValueError si vous utilisez inspect.getfullargspec() sur une fonction intégrée.

Depuis Python 3.3, vous pouvez utiliser inspect.signature() pour voir la signature d'appel d'un objet appelable :

>>> inspect.signature(foo)
<Signature (a, b, c=4, *arglist, **keywords)>

1 votes

Voir aussi stackoverflow.com/a/3999574/288875 sur l'examen des callables en général

37 votes

Comment le code pourrait-il savoir que le paramètre par défaut (4,) correspond au paramètre mot-clé c spécifiquement ?

74 votes

@fatuhoku Je me demandais la même chose. Il s'avère que ce n'est pas ambigu puisque vous pouvez seulement ajouter des arguments par défaut à la fin dans un bloc contigu. Extrait de la docs : "si ce tuple a n éléments, ils correspondent aux n derniers éléments listés dans args"

102voto

Jouni K. Seppänen Points 15129

En CPython, le nombre d'arguments est le suivant

a_method.func_code.co_argcount

et leurs noms sont au commencement de

a_method.func_code.co_varnames

Ce sont des détails d'implémentation de CPython, donc cela ne fonctionne probablement pas dans d'autres implémentations de Python, comme IronPython et Jython.

Une façon portable d'admettre les arguments "pass-through" est de définir votre fonction avec la signature func(*args, **kwargs) . On l'utilise souvent, par exemple, dans les cas suivants matplotlib où la couche externe de l'API transmet de nombreux arguments sous forme de mots-clés à l'API de niveau inférieur.

0 votes

Co_varnames fonctionne avec Python standard, mais cette méthode n'est pas préférable car elle affichera également les arguments internes.

12 votes

Pourquoi ne pas utiliser aMethod.func_code.co_varnames[:aMethod.func_code.co_argcount] ?

0 votes

Ne fonctionne pas avec les arguments après *args par exemple : def foo(x, *args, y, **kwargs): # foo.__code__.co_argcount == 1

23voto

Mehdi Behrooz Points 351

Dans une méthode décorateur, vous pouvez énumérer les arguments de la méthode originale de cette manière :

import inspect, itertools 

def my_decorator():

        def decorator(f):

            def wrapper(*args, **kwargs):

                # if you want arguments names as a list:
                args_name = inspect.getargspec(f)[0]
                print(args_name)

                # if you want names and values as a dictionary:
                args_dict = dict(itertools.izip(args_name, args))
                print(args_dict)

                # if you want values as a list:
                args_values = args_dict.values()
                print(args_values)

Si le **kwargs sont importantes pour vous, alors ce sera un peu compliqué :

        def wrapper(*args, **kwargs):

            args_name = list(OrderedDict.fromkeys(inspect.getargspec(f)[0] + kwargs.keys()))
            args_dict = OrderedDict(list(itertools.izip(args_name, args)) + list(kwargs.iteritems()))
            args_values = args_dict.values()

Ejemplo:

@my_decorator()
def my_function(x, y, z=3):
    pass

my_function(1, y=2, z=3, w=0)
# prints:
# ['x', 'y', 'z', 'w']
# {'y': 2, 'x': 1, 'z': 3, 'w': 0}
# [1, 2, 3, 0]

3 votes

Cette réponse est partiellement obsolète et devrait être mise à jour.

16voto

Damian Points 535

Je pense que ce que tu cherches est la méthode des locaux -

In [6]: def test(a, b):print locals()
   ...: 

In [7]: test(1,2)              
{'a': 1, 'b': 2}

10 votes

Ceci est inutile en dehors d'une fonction qui est le contexte qui nous intéresse ici (décorateur).

9 votes

En fait, c'est exactement ce que je cherchais, même si ce n'est pas la réponse à la question posée ici.

13voto

kevin holzer Points 189

Voici quelque chose qui, je pense, correspondra à ce que vous voulez, en utilisant un décorateur.

class LogWrappedFunction(object):
    def __init__(self, function):
        self.function = function

    def logAndCall(self, *arguments, **namedArguments):
        print "Calling %s with arguments %s and named arguments %s" %\
                      (self.function.func_name, arguments, namedArguments)
        self.function.__call__(*arguments, **namedArguments)

def logwrap(function):
    return LogWrappedFunction(function).logAndCall

@logwrap
def doSomething(spam, eggs, foo, bar):
    print "Doing something totally awesome with %s and %s." % (spam, eggs)

doSomething("beans","rice", foo="wiggity", bar="wack")

Exécutez-le, il produira le résultat suivant :

C:\scripts>python decoratorExample.py
Calling doSomething with arguments ('beans', 'rice') and named arguments {'foo':
 'wiggity', 'bar': 'wack'}
Doing something totally awesome with beans and rice.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X