La description

Disons que j'ai la fonction suivante, qui appelle une autre fonction:

def f1(arg1, arg2, arg3):
    f2(...)

Les arguments de f1 et f2 sont identiques, ou f2 pourrait ressembler à ceci:

def f2(**kwargs)
    pass  # whatever

Le code client va définir et appeler f1, et il est nécessaire que la signature de f1 définisse explicitement tous les arguments, et donc aucun **kwargs n'est autorisé pour f1.

Donc, pour appeler f2 de l'intérieur f1, je dois faire ceci:

def f1(arg1, arg2, arg3):
    f2(arg1, arg2, arg3)

Question

Existe-t-il un moyen de transmettre des arguments à f2 sans les écrire explicitement? Idéalement, je pense que cela devrait ressembler à ceci:

def f1(arg1, arg2, arg3):
        kwargs = <Some Magic Here>
        f2(**kwargs)

De la magie?

MISE À JOUR

Solution possible

Existe-t-il un moyen de combiner locals() et inspect.getargspec() pour agréger mes **kwargs?

3
bagrat 19 juil. 2015 à 18:24

3 réponses

Meilleure réponse

En général

Eh bien, vous pouvez créer kwargs comme dictionnaire de tous les arguments que f2() accepte et le transmettre. Bien que je ne vois aucun avantage à cela, en utilisant -

def f1(arg1, arg2, arg3):
    f2(arg1=arg1, arg2=arg2, arg3=arg3)

Cela me semble bien et serait plus facile que de construire le dictionnaire et de l'appeler comme **kwargs.

Quoi qu'il en soit, la façon de le faire est -

>>> def a(a,b,c):
...     kwargs = {'a':a , 'b':b , 'c':c}
...     d(**kwargs)
...
>>> def d(**kwargs):
...     print(kwargs)
...
>>> a(1,2,3)
{'c': 3, 'a': 1, 'b': 2}

Pour votre cas d'utilisation

Le problème est que f1 va être défini par le client, le traitement de l'argument est commun à tous, donc je veux cacher les détails du traitement, afin que le client passe tous les arguments à l'implémentation. De plus, je veux faciliter la définition et passer automatiquement tous les arguments et ne pas les spécifier explicitement.

locals() à l'intérieur d'une fonction vous renvoie la copie des variables locales de la fonction à ce moment-là sous forme de dictionnaire. Si, comme dans votre question, si les définitions de f1() et f2() sont les mêmes, vous pouvez utiliser locals(), en l'appelant au début de la fonction avant tout autre code. Exemple -

>>> def a(a,b,c):
...     lcl = locals()
...     print(lcl)
...     d(**lcl)
...     e = 123
...     print(locals())
...
>>> def d(**kwargs):
...     print(kwargs)
...
>>> a(1,2,3)
{'c': 3, 'a': 1, 'b': 2}
{'c': 3, 'a': 1, 'b': 2}
{'c': 3, 'a': 1, 'e': 123, 'lcl': {...}, 'b': 2}
2
bagrat 19 juil. 2015 à 16:46

Voici comment j'ai résolu mon problème en fonction de la réponse d'Anand S Kumar ainsi que de Réponse d'Alex Martelli à une autre question:

def f2():
    kwargs = inspect.getouterframes(inspect.currentframe(), 2)[1][0].f_locals
    print(kwargs)

def f1(arg1, arg2, arg3)
    f2()  # this should be called right at the first line

>>> f1(1, 2, 3)
{'arg1': 1, 'arg2': 2, 'arg3': 3}
1
Community 23 mai 2017 à 12:30

Ce que vous voulez ici, c'est passer les arguments de la fonction parent à une fonction englobante. Donc, je dois dire que vous ne pouvez pas utiliser local() parce que local est contient les variables locales qui contiennent l'argument et tout les variables locales que vous avez définies dans votre copain de fonction, mais si vous voulez simplement obtenir tous les arguments quand ils sont dynamiques et comme votre exemple, je suggère d'utiliser *args dans la fonction parents:

def f1(*args):

Mais il y a un point ici, puisque vous voulez utiliser **kwargs et c'est pour collecter les arguments de mots-clés arbitrairement dont vous avez besoin pour initialiser les noms de votre argument.

Par exemple, vous pouvez utiliser une compréhension dict comme suit:

def f1(*args):
        kwargs = {'arg{}'.format(i):j for i,j in enumerate(args,1)}
        f2(**kwargs)

De plus, si vous êtes sûr qu'il n'y a pas de variable locale dans votre copain de fonction spécialement avant de définir la fonction englobante, vous pouvez utiliser locals:

Exemple :

>>> globsl_a=8
>>> def fun(arg1,arg2,arg3):
...   print locals()
... 
>>> fun(5,[3,4],'text')
{'arg1': 5, 'arg2': [3, 4], 'arg3': 'text'}
>>> 
1
Kasramvd 19 juil. 2015 à 15:45