Pouvez-vous lister les arguments de mots clés qu'une fonction reçoit?

j'ai un dict, que je dois passer clé/valeurs comme arguments de mot-clé.. Exemple..

d_args = {'kw1': 'value1', 'kw2': 'value2'}
example(**d_args)

cela fonctionne très bien, mais s'il y a des valeurs dans le d_args dict qui ne sont pas acceptées par la fonction example , il meurt évidemment.. Disons, si la fonction d'exemple est définie comme def example(kw2):

C'est un problème car je ne contrôle ni la génération du d_args , ni celle du example ." fonction.. Ils viennent tous les deux de modules externes, et example n'accepte que certains des mots-clés-arguments du dict..

Idéalement, je voudrais juste faire

parsed_kwargs = feedparser.parse(the_url)
valid_kwargs = get_valid_kwargs(parsed_kwargs, valid_for = PyRSS2Gen.RSS2)
PyRSS2Gen.RSS2(**valid_kwargs)

je vais probablement juste filtrer le dict, à partir d'une liste d'arguments-mots-clés valides, mais je me demandais: y a-t-il un moyen de programmer les arguments-mots-clés que prend une fonction spécifique?

87
demandé sur martineau 2008-10-13 11:55:18

5 réponses

un peu plus agréable que d'inspecter l'objet de code directement et de travailler sur les variables est d'utiliser le module d'inspection.

>>> import inspect
>>> def func(a,b,c=42, *args, **kwargs): pass
>>> inspect.getargspec(func)
(['a', 'b', 'c'], 'args', 'kwargs', (42,))

si vous voulez savoir si son callable avec un ensemble particulier d'args, vous avez besoin de l'args sans un défaut déjà spécifié. On peut les obtenir par:

def getRequiredArgs(func):
    args, varargs, varkw, defaults = inspect.getargspec(func)
    if defaults:
        args = args[:-len(defaults)]
    return args   # *args and **kwargs are not required, so ignore them.

alors une fonction pour dire ce que vous manquez de votre dict particulier est:

def missingArgs(func, argdict):
    return set(getRequiredArgs(func)).difference(argdict)

de Même, pour vérifier args invalide, utiliser:

def invalidArgs(func, argdict):
    args, varargs, varkw, defaults = inspect.getargspec(func)
    if varkw: return set()  # All accepted
    return set(argdict) - set(args)

et donc un test complet si elle est appelable est:

def isCallableWithArgs(func, argdict):
    return not missingArgs(func, argdict) and not invalidArgs(func, argdict)

(C'est bon uniquement pour python arg de l'analyse. Tous les contrôles d'exécution pour les valeurs invalides en kwargs ne peuvent évidemment pas être détectés.)

120
répondu Brian 2008-10-13 09:12:50

ceci imprimera les noms de tous les arguments passables, mots clés et non-mots clés ceux:

def func(one, two="value"):
    y = one, two
    return y
print func.func_code.co_varnames[:func.func_code.co_argcount]

c'est parce que les premiers co_varnames sont toujours des paramètres (les variables suivantes sont des variables locales, comme y dans l'exemple ci-dessus).

donc maintenant vous pouvez avoir une fonction:

def getValidArgs(func, argsDict):
    '''Return dictionary without invalid function arguments.'''
    validArgs = func.func_code.co_varnames[:func.func_code.co_argcount]
    return dict((key, value) for key, value in argsDict.iteritems() 
                if key in validArgs)

que vous pourriez alors utiliser comme ceci:

>>> func(**getValidArgs(func, args))

modifier : un petit ajout: si vous n'avez vraiment besoin que des arguments de mots clés d'une fonction, vous pouvez utiliser l'attribut func_defaults pour les extraire:

def getValidKwargs(func, argsDict):
    validArgs = func.func_code.co_varnames[:func.func_code.co_argcount]
    kwargsLen = len(func.func_defaults) # number of keyword arguments
    validKwargs = validArgs[-kwargsLen:] # because kwargs are last
    return dict((key, value) for key, value in argsDict.iteritems() 
                if key in validKwargs)

vous pouvez maintenant appeler votre fonction avec des args connus, mais extrait des kwargs, par exemple:

func(param1, param2, **getValidKwargs(func, kwargsDict))

cela suppose que func n'utilise pas de magie *args ou **kwargs dans sa signature.

28
répondu DzinX 2008-10-13 08:41:59

En Python 3.0:

>>> import inspect
>>> import fileinput
>>> print(inspect.getfullargspec(fileinput.input))
FullArgSpec(args=['files', 'inplace', 'backup', 'bufsize', 'mode', 'openhook'],
varargs=None, varkw=None, defaults=(None, 0, '', 0, 'r', None), kwonlyargs=[], 
kwdefaults=None, annotations={})
6
répondu jfs 2008-10-13 09:32:56

extension de la réponse de DzinX:

argnames = example.func_code.co_varnames[:func.func_code.co_argcount]
args = dict((key, val) for key,val in d_args.iteritems() if key in argnames)
example(**args)
3
répondu Claudiu 2008-10-13 08:20:20

pour une solution Python 3, vous pouvez utiliser inspect.signature et filtrer selon le genre de paramètres que vous aimeriez connaître.

prise d'un exemple de fonction avec des paramètres de position ou mot clé, mot clé seulement, position var et mot clé var:

def spam(a, b=1, *args, c=2, **kwargs):
    print(a, b, args, c, kwargs)

vous pouvez créer un objet signature pour elle:

from inspect import signature
sig =  signature(spam)

et filtrer ensuite avec une liste compréhension pour connaître les détails dont vous avez besoin:

>>> # positional or keyword
>>> [p.name for p in sig.parameters.values() if p.kind == p.POSITIONAL_OR_KEYWORD]
['a', 'b']
>>> # keyword only
>>> [p.name for p in sig.parameters.values() if p.kind == p.KEYWORD_ONLY]
['c']

et, de même, pour les positionnels var utilisant p.VAR_POSITIONAL et le mot-clé var avec VAR_KEYWORD .

en outre, vous pouvez ajouter une clause au SI pour vérifier si une valeur par défaut existe en vérifiant si p.default égale p.empty .

2
répondu Jim Fasarakis Hilliard 2017-07-28 12:01:19