ラムダ関数が可変数の引数を持つことは可能ですか?たとえば、他のクラスのすべてのメソッドのメソッドを作成し、この新しく作成されたメソッドが元のメソッドの反対の値を返し、同じ数の引数を持つメタクラスを作成したいとします。そして、ラムダ関数でこれを実行したいと思います。引数を渡す方法は?出来ますか?
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
しかし、結果は完全に間違っています。
>>>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
ラムダ関数で可変引数を使用しても問題はありません。ここでの問題は異なります:
問題は、ラムダがループ変数v
を参照することです。しかし、ラムダが呼び出されるまでに、v
の値が変更され、ラムダが間違った関数を呼び出します。これは、ループでラムダを定義するときに常に注意する必要があります。
クロージャにv
の値を保持する追加の関数を作成することで、これを修正できます。
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)
はい。
>>> l = lambda *x: print(x)
>>> l(1,2,3)
(1, 2, 3)