2009-12-27 2 views
1

Je ne veux pas utiliser * args ou kwargs ** depuis que je ne peux pas changer la déclaration de fonction.En python, est-il possible d'obtenir les arguments passés à une fonction en tant qu'objet?

Par exemple:

def foo(a, b, c) """Lets say values passed to a, b and c are 1,2 and 3 respectively""" 
    ... 
    ... 
    """ I would like to generate an object preferably a dictionary such as {'a':1, 'b':2, 'c':3} """ 
    ... 
    ... 

Quelqu'un peut-il suggérer une façon de le faire? Merci d'avance.

Répondre

5

Si vous ne pouvez pas changer la fonction « déclaration » mais vous pouvez modifier le contenu de la fonction, il suffit de créer le dictionnaire que vous voulez (pourquoi pas?):

def foo(a, b, c): 
    mydict = {'a': a, 'b': b, 'c': c} 

Si cela ne Ne travaillez pas, je pense que vous avez besoin d'une meilleure explication de ce que vous voulez et quelles sont les contraintes dans votre cas.

Cela va également donner des résultats similaires dans le cas ci-dessus (où vous ne vous présentez pas de variables locales autres que les arguments), mais il faut savoir que you should not try to modify locals():

def foo(a, b, c): 
    mydict = locals() 
+1

Impossible une copie des 'locals()' dict résoudre le problème, à savoir 'mondict = locals(). Copy()'? Au moins le problème de ne pas modifier 'mydict'? – ndim

+0

@ndim, oui, cela fonctionnerait bien pour éviter le problème de la modification des locaux(). Nous ne pouvons pas savoir si cela aiderait le PO, compte tenu du peu qu'il a donné jusqu'ici. –

+0

>>> >>> def toto (a, b, c): ... mydict = locals() ... mydict ['a'] = 0 ...print mondict ... imprimer un ... >>> >>> foo (1,2,3) { 'a': 0, 'c': 3, 'b': 2} >>> ressemble à je viens de modifier mydict .. et il n'a pas jeté d'erreurs !! – Nullpoet

0
def foo(a, b, c): 
    args = {"a": a, "b": b, "c": c} 
+0

Je le veux pour n'importe quelle fonction générale. – Nullpoet

+1

Il y a probablement un meilleur moyen que ce que vous avez demandé pour réaliser ce que vous voulez vraiment faire. (Un objet pour tous les paramètres est un moyen, pas une fin.) Tant que vous ne demandez pas ce que vous voulez vraiment, nous ne pouvons pas faire grand-chose pour vous aider. –

1

@Rohit , nous ne comprenons pas ce que vous voulez dire quand vous dites "la déclaration de fonction". Si vous voulez dire que vous ne voulez pas changer l'API de la fonction (la manière documentée la fonction est appelée), peut-être parce que vous avez le code existant appelant déjà une fonction existante, vous pouvez toujours utiliser la notation **kwargs, et les appelants seront ne sait jamais:

def foo(a, b, c): 
    return a + b + c 

def foo(**kwargs): 
    total = 0 
    for x in ("a", "b", "c"): 
     assert x in kwargs 
     total += kwargs[x] 
    return total 

def bar(): 
    foo(3, 5, 7) 

bar() ne peut pas dire quelle version de foo() il appelle, et ne se soucie pas.

Peut-être que vous cherchez un « emballage », vous pouvez enrouler autour des objets fonctionnels existants, sans modifier le code source de l'objet de la fonction?

def make_wrapper(fn, *arg_names): 
    def wrapped_fn(*args): 
     mydict = dict(tup for tup in zip(arg_names, args)) 
     print("TEST: mydict: %s" % str(mydict)) 
     return fn(*args) 
    return wrapped_fn 


def foo(a, b, c): 
    return a + b + c 

foo = make_wrapper(foo, "a", "b", "c") 

foo(3, 5, 7) 

La nouvelle fonction enveloppé rassemble les arguments en mydict et imprime mydict avant d'appeler la fonction.

+0

@steveha Merci pour les détails .. et oui en fait je veux une fonction wrapper, mais je ne veux pas ajouter un appel à make_wrapper chaque fois que j'ajoute une nouvelle fonction .. Je vais aller avec un décorateur qui collecterait toutes les entrées arguments dans un dictionnaire ... avec "locals()" comme première instruction dans la fonction décorateur. – Nullpoet

+0

Je ne sais pas comment écrire le décorateur que vous voulez. Si vous utilisez '* args' pour collecter les arguments dans la fonction wrapper, vous n'obtenez pas les noms des arguments (c'est pourquoi je vous ai demandé de passer les noms d'arguments à la fonction' make_wrapper() '). Ce que vous voulez vraiment, c'est un instantané du résultat de l'appel 'locals()' de * à l'intérieur * de la fonction enveloppée; vous ne pouvez pas l'obtenir avant que la fonction ne soit appelée ou après son retour. Peut-être que la solution parfaite nécessiterait de pirater les bytecodes Python! Il pourrait y avoir quelque chose dans le livre de recettes Python. – steveha

1

En effectuant une recherche diligente de StackOverflow, je found out comment faire cela. Vous utilisez le module inspect.

import inspect 

def make_wrapper(fn): 
    arg_names = inspect.getargspec(fn)[0] 
    def wrapped_fn(*args, **kwargs): 
     # mydict now gets all expected positional arguments: 
     mydict = dict(tup for tup in zip(arg_names, args)) 
     # special name "__args" gets list of all positional arguments 
     mydict["__args"] = args 
     # mydict now updated with all keyword arguments 
     mydict.update(kwargs) 
     # mydict now has full information on all arguments of any sort 
     print("TEST: mydict: %s" % str(mydict)) 
     return fn(*args, **kwargs) 
    return wrapped_fn 

def foo(a, b, c, *args, **kwargs): 
    # a, b, and c must be set; extra, unexpected args will go in args list 
    return a + b + c 

foo = make_wrapper(foo) 

foo(3, 5, 7, 1, 2) 
# prints: TEST: mydict: {'a': 3, 'c': 7, 'b': 5, '__args': (3, 5, 7, 1, 2)} 
# returns: 15 

Voilà, une solution parfaite au problème que vous avez indiqué. C'est un wrapper, vous n'avez pas besoin de passer dans les arguments, et cela devrait fonctionner pour n'importe quelle fonction. Si vous en avez besoin pour travailler avec des objets de classe ou quelque chose, vous pouvez lire les documents pour inspect et voir comment le faire.

Note, de l'ordre cours n'est pas conservé dans les dictionnaires, de sorte que vous ne pouvez pas voir l'ordre exact que j'ai vu quand je l'ai testé cela. Mais les mêmes valeurs devraient être dans le dict.

Questions connexes