2008-10-13 11 views
81

J'ai un dict, que je dois transmettre des valeurs clés/comme arguments mot-clé .. Par exemple ..Pouvez-vous lister les arguments que reçoit une fonction Python?

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

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

Ceci est un problème que je ne contrôle pas non plus la génération du d_args, ou la fonction example .. Ils ont tous deux venir à partir de modules externes, et example n'accepte que certains des mots-clés en om 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 filtrer juste le dict, à partir d'une liste de mots clés arguments valables, mais je me demandais: Y at-il un moyen de programatically liste les arguments de mot-clé qu'une fonction spécifique prend?

Répondre

114

Un peu plus agréable que d'inspecter l'objet de code directement et de travail variables est d'utiliser le module inspecter.

>>> 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 appelable avec un ensemble particulier de args, vous avez besoin args sans défaut déjà spécifié.Ceux-ci peuvent être obtenus 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. 

Ensuite, une fonction de 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 invalides, utilisez:

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) 

(Ceci n'est bon que jusqu'à l'analyse des arguments de python. Tous les contrôles d'exécution pour les valeurs non valides dans kwargs ne peuvent évidemment pas être détectés)

+0

Nice! Je ne connaissais pas cette fonction! – DzinX

+0

Je crois que cela mérite d'être la réponse acceptée. – codeape

+1

Étant donné que la méthode utilisant des objets de code est plus ou moins identique, y a-t-il un avantage à devoir importer un module de plus ...? – jmetz

28

Cela affichera les noms de tous les arguments carrossables, mot-clé et les non-mots:

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

En effet, la première co_varnames sont toujours les paramètres (à côté sont des variables locales, comme y dans l'exemple ci-dessus).

Alors maintenant, vous pourriez 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)) 

EDIT: Un petit plus: si vous vraiment besoin seuls les arguments de mot-clé 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 args connues, mais extraites kwargs, .: par exemple

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

Cela suppose que func utilise pas *args ou **kwargs magique dans sa signature.

3

L'extension de la réponse 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) 
6

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={}) 
0

Pour une solution Python 3, vous pouvez utiliser inspect.signature et le filtre selon the kind of parameters vous souhaitez A connaître.

Prendre une fonction d'échantillonnage avec position ou mot-clé, uniquement des mots clés, var paramètres de position 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 de signature pour elle:

from inspect import signature 
sig = signature(spam) 

puis filtrer avec une compréhension de la liste 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 positions var utilisant p.VAR_POSITIONAL et var mot-clé avec VAR_KEYWORD.

En outre, vous pouvez ajouter une clause à l'if pour vérifier si une valeur par défaut existe en vérifiant si p.default est égal à p.empty.

Questions connexes