2010-05-26 6 views
19

Est-il possible qu'une fonction lambda ait un nombre variable d'arguments? Par exemple, je veux écrire une métaclasse, qui crée une méthode pour chaque méthode d'une autre classe et cette méthode nouvellement créée renvoie la valeur opposée de la méthode d'origine et a le même nombre d'arguments. Et je veux le faire avec la fonction lambda. Comment passer les arguments? C'est possible?varargs dans les fonctions lambda en Python

class Negate(type): 
    def __new__(mcs, name, bases, _dict): 
     extended_dict = _dict.copy() 
     for (k, v) in _dict.items(): 
      if hasattr(v, '__call__'): 
       extended_dict["not_" + k] = lambda s, *args, **kw: not v(s, *args, **kw) 
     return type.__new__(mcs, name, bases, extended_dict) 

class P(metaclass=Negate): 
    def __init__(self, a): 
     self.a = a 

    def yes(self): 
     return True 

    def maybe(self, you_can_chose): 
     return you_can_chose 

Mais le résultat est tout à fait tort: ​​

>>>p = P(0) 
>>>p.yes() 
True 
>>>p.not_yes()  # should be False 
Traceback (most recent call last): 
    File "<pyshell#150>", line 1, in <module> 
    p.not_yes() 
    File "C:\Users\Desktop\p.py", line 51, in <lambda> 
    extended_dict["not_" + k] = lambda s, *args, **kw: not v(s, *args, **kw) 
TypeError: __init__() takes exactly 2 positional arguments (1 given) 
>>>p.maybe(True) 
True 
>>>p.not_maybe(True)  #should be False 
True 

Répondre

27

Il n'y a pas de problème à l'aide varargs dans les fonctions lambda. Le problème ici est différent:

Le problème est que le lambda réfrène la variable de boucle v. Mais au moment où le lambda est appelé, la valeur de v a changé et le lambda appelle la mauvaise fonction. C'est toujours quelque chose à surveiller lorsque vous définissez un lambda dans une boucle.

Vous pouvez résoudre ce problème en créant une fonction supplémentaire qui contiendra la valeur de v dans une fermeture:

def create_not_function(v): 
    return lambda s, *args, **kw: not v(s, *args, **kw) 

for (k, v) in _dict.items(): 
    if hasattr(v, '__call__'): 
     extended_dict["not_" + k] = create_not_function(v) 
+0

Lien pertinent: http://code.activestate.com/recipes/502271/ –

10

Oui.

>>> l = lambda *x: print(x) 
>>> l(1,2,3) 
(1, 2, 3) 
+1

Notez que cela fonctionnera uniquement avec Python3. Cette syntaxe n'est pas supportée dans Python2. – wohlgejm

+2

Plus précisément, 'lambda * x:' fonctionnera en Python 2, mais 'print' à l'intérieur d'un lambda ne fonctionne que dans Python 3. – kennysong

+0

Notez que dans' print (x) ', il affichera les arguments sous la forme d'un tuple, 'print (* x)' appelle l'impression avec les arguments décompressés. –