94 votes

Récupérer tous les arguments et valeurs passés à une fonction

J'ai une fonction Python, fetch_data qui se connecte à une API distante, récupère des données et les renvoie dans un objet de réponse. Cela ressemble un peu à ce qui suit :

def fetch_data(self, foo, bar, baz, **kwargs):
    response = Response()
    # Do various things, get some data
    return response

Maintenant, il est possible que les données de réponse disent "J'ai plus de données, appelez-moi avec une incrémentation page paramètre pour en obtenir plus". Ainsi, j'aimerais essentiellement stocker "l'appel de la méthode" (fonction, paramètres) dans l'objet de réponse, de sorte que je puisse ensuite avoir une Response.get_more() qui examine la fonction stockée et les paramètres, et appelle à nouveau la fonction avec (presque) les mêmes paramètres, en renvoyant un nouveau fichier Response

Maintenant si fetch_data ont été définis comme suit fetch_data(*args, **kwargs) Je pourrais juste stocker (fetch_data, args, kwargs) en response . Cependant, j'ai self , foo , bar et baz de s'inquiéter - je pourrais simplement stocker (fetch_data, foo, bar, baz, kwargs) mais c'est une quantité de répétition hautement indésirable.

Essentiellement, j'essaie de trouver comment, à partir d'une fonction, obtenir une image complètement remplie. *args et **kwargs y compris les paramètres nommés de la fonction.

141voto

kuzzooroo Points 507

Essentiellement, j'essaie de trouver comment, à partir d'une fonction, obtenir un *args et un **kwargs complètement remplis, y compris les paramètres nommés de la fonction.

Que diriez-vous de sauvegarder les arguments via locals() au début de la fonction ?

def my_func(a, *args, **kwargs):
    saved_args = locals()
    print("saved_args is", saved_args)
    local_var = 10
    print("saved_args is", saved_args)
    print("But locals() is now", locals())

my_func(20, 30, 40, 50, kwarg1='spam', kwarg2='eggs')

Il donne ce résultat :

saved_args is {'a': 20, 'args': (30, 40, 50), 'kwargs': {'kwarg1': u'spam', 'kwarg2': u'eggs'}}
saved_args is {'a': 20, 'args': (30, 40, 50), 'kwargs': {'kwarg1': u'spam', 'kwarg2': u'eggs'}}
But locals is now {'a': 20, 'saved_args': {...}, 'args': (30, 40, 50), 'local_var': 10, 'kwargs': {'kwarg1': u'spam', 'kwarg2': u'eggs'}}

Conseil du chapeau : https://stackoverflow.com/a/3137022/2829764

45voto

Martijn Pieters Points 271458

Ce n'est pas quelque chose que je ferais, mais vous pourriez utiliser inspect.signature pour introspecter les arguments que votre méthode prend :

>>> import inspect
>>> def foobar(foo, bar, baz):
...     return inspect.signature(foobar)
... 
>>> foobar(1, 2, 3)
<Signature (foo, bar, baz)>

Le retour Signature instance a une collection ordonnée de paramètres (le .parameters attribut ) qui peut ensuite être utilisé avec locals() pour produire une liste des valeurs de vos arguments :

>>> def foobar(foo, bar, baz):
...     sig, foobar_locals = inspect.signature(foobar), locals()
...     return [foobar_locals[param.name] for param in sig.parameters.values()]
...
>>> foobar(1, 2, 3)
[1, 2, 3]

Cependant, vous n'avez vraiment besoin de cette magie que pour les décorateurs de fonctions avancées et autres. Je pense que c'est exagéré ici.

26voto

JDG Points 318

Je ne suis pas sûr que ce soit exactement ce que vous voulez, mais locals() fournit un dictionnaire de variables locales.

>>> def foo(bar, toto):
...     print(locals())
...
>>> foo(3,'sometext')
{'toto': 'sometext', 'bar': 3}

15voto

NPE Points 169956

Je pense qu'une manière plus Pythonique est de transformer votre fonction en un générateur, récupérant et yield tant que le serveur continue à renvoyer des données.

Cela devrait donner un code soigné et vous permettre d'éviter toute la complexité de la préservation des arguments entre les itérations (Python le fera magiquement pour vous :-)).

12voto

German Lashevich Points 866

inspect.getargspec est déprécié depuis la version 3.0. Utilisez signature() et Signature Object, qui fournissent une meilleure API d'introspection pour les appelables.

>>> from inspect import signature
>>> def foo(a, *, b:int, **kwargs):
...     pass

>>> sig = signature(foo)

>>> str(sig)
'(a, *, b:int, **kwargs)'

>>> str(sig.parameters['b'])
'b:int'

>>> sig.parameters['b'].annotation
<class 'int'>

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