Ajouter un argument a une fonction

a marqué ce sujet comme résolu.

Bonjour,

J'ai un petit soucis avec Python 2.

Je cherche a ajouter une argument, avec valeur par defaut, a une signature de fonction (quelque soit cette fonction et sa signature), et que cet argument soit a la fin de la nouvelle signature.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
    def inject(function):
        def wrap_function(*args, **kwargs, c=False):
            print c
            return function(*args, **kwargs)
        return wrap_function

    @inject
    def test(a, b):
        print a, b

    test(a,b) #OK c = False
    test(a, b, c=True) # OK

Pour le moment, je n'ai reussi qu'a obtenir cela:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
    def inject(function):
        def wrap_function(c, *args, **kwargs):
            print c
            return function(warg)
        return wrap_function

    @inject
    def test(a, b):
        print a, b

    test(True, 1, 2)

C'est bien sur embetant pour les signatures des fonctions deja existantes que je devrais modifier dans mon code et par le fait que je ne peux pas utiliser de valeur par defaut.

Une idee en Python 2 ?

EDIT:

Bon en fait j'ai fait comme ceci, avec pour convention que le nouvel argument sera a la fin (c'est pas tres secure m'enfin…):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
def inject(function):
    import inspect
    @wraps(function)
    def wrap_function(*args, **kwargs):
        c = False
        if 'c' in kwargs:
            c = kwargs['c']
            del kwargs['c']
        else:
            fargs = inspect.getargspec(function)
            if len(fargs.args) < len(args):
                c = True
                args = args[:-1]
        return function(*args, **kwargs)
    return wrap_function

Je prends toute autre idee ou amelioration.

+0 -0

C'etait une erreur de typo. Je supprinme effectivement l'argument s'il est dans kwargs, et sinon je regarde s'il y a un parameter supplementaire positionnel. Si oui, je considere par convention que c'est le dernier qui a ete ajoute. Je le retire alors.

Dams les deux cas la signature de la methode decoree est respectee.

Pourquoi ne pas obliger à utiliser un paramètre nommé ? Ce serait bien plus ressemblant à ce que tu voulais au début non ? Ou c'est que tu veux aussi pouvoir écrire test(1,2,True)… Si c'est ça, je ne vois pas comment rendre ça plus propre (peut être passer le nombre d'args non nommés en arguments à ton décorateur)

Ce que j'aurais fais (le 1 ou le 2 selon mes besoins) avec une prédérence pour le 1 (BEAUCOUP plus court), bonne chance pour la suite

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
a,b = (1,2)
def inject1(fct):
        def wrap_fct(*args, **kargs):
            c = kargs.pop('c', False)
            print 'c :', c
            fct(*args, **kargs)
        return wrap_fct

@inject1
def test1(a,b):
    print a, b

def inject2(argsNbr):
    def _(fct):
        def wrap_fct(*args, **kargs):
            c = False
            if 'c' in kargs:
                c = kargs.pop('c')
            elif argsNbr < len(args):
                c = args[-1]
                args = args[:-1]

            print 'c :', c
            fct(*args, **kargs)
        return wrap_fct
    return _

@inject2(2)
def test2(a,b):
    print a, b

print "TEST 1"
test1(a,b)
# FAIL ! test1(a,b,True)
test1(a,b, c=True)

print "\nTEST 2"
test2(a,b)
test2(a,b,True)
test2(a,b, c=True)

La premiere solution n'est pas possible car il ne me faut pas supporter uniquement les arguments nommes. La seconde n'est pas possible non plus car je ne connais pas le nombre d'arguments ni certains seront nommes ou simplement positionnels.

En fait ma solution convient, mais je prends le pop au lieu de l'acces + del.

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte