2010-05-26 31 views
19

Có thể hàm lambda có số lượng đối số biến không? Ví dụ, tôi muốn viết một metaclass, tạo ra một phương thức cho mọi phương thức của một số lớp khác và phương thức mới được tạo này trả về giá trị ngược của phương thức gốc và có cùng số đối số. Và tôi muốn làm điều này với hàm lambda. Làm thế nào để vượt qua các đối số? Có thể không?varargs trong hàm lambda trong 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 

Nhưng kết quả là hoàn toàn sai:

>>>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 

Trả lời

27

Không có vấn đề sử dụng varargs trong các hàm lambda. Vấn đề ở đây là khác nhau:

Vấn đề ở chỗ lambda điều chỉnh biến vòng lặp v. Nhưng vào thời điểm lambda được gọi, giá trị của v đã thay đổi và hàm lambda gọi hàm sai. Điều này luôn luôn là một cái gì đó để xem ra khi bạn xác định một lambda trong một vòng lặp.

Bạn có thể khắc phục điều này bằng cách tạo ra một chức năng bổ sung mà sẽ giữ giá trị của v trong một đóng cửa:

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

Liên quan có liên quan: http://code.activestate.com/recipes/502271/ –

10

Yes.

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

Lưu ý rằng thao tác này sẽ chỉ hoạt động với Python3. Cú pháp này không được hỗ trợ trong Python2. – wohlgejm

+2

Chính xác hơn, 'lambda * x:' sẽ hoạt động trong Python 2, nhưng 'in' bên trong một lambda chỉ hoạt động trong Python 3. – kennysong

+0

Lưu ý rằng trong' print (x) ', nó sẽ in các đối số dưới dạng bộ tuple, trong khi 'print (* x)' sẽ gọi in với các đối số được giải nén. –