2010-07-07 37 views
6

Có lẽ tôi nhận được điều này hoàn toàn sai nhưng tôi chạy vào một số vấn đề kỳ lạ với lambda gọi @classmethod.gọi lambda @classmethod thất bại

Tôi có lớp sau đây:

class MyClass: 
    LAMBDA = lambda: MyClass.ClassMethod() 

    @classmethod 
    def ClassMethod(cls): 
    pass 

Nhưng điều này không bất cứ khi nào LAMBDA được gọi với:

TypeError: unbound method <lambda>() must be called with MyClass instance as first argument (got nothing instead) 

Tôi thực sự không hiểu tại sao điều này là như vậy. Tôi đã dành chút thời gian để làm việc đó. Tôi cần một số thuộc tính lớp được phổ biến bởi lambda đó và tự tham khảo lớp học rõ ràng là không thể ở giai đoạn đó.

+0

FYI, Điều này hoạt động trên Python 3, nhưng không phải trên Python 2. – kennytm

+0

@KennyTM, Nó hoạt động trên Python 3 bởi trùng hợp ngẫu nhiên. Python 3 đã loại bỏ phương thức bị ràng buộc và chỉ trả về chính hàm đó. Mặc dù đây là một quyết định thiết kế tốt, nó là khái niệm iffy lúc tốt nhất để sử dụng nó để làm cho staticmethods giả. –

Trả lời

2

Bạn phải hiểu, rằng mã của bạn là chính xác tương đương với

class MyClass: 

    def LAMBDA(): 
    return MyClass.ClassMethod() 

    @classmethod 
    def ClassMethod(cls): 
    pass 

Bạn, sau đó, rõ ràng gọi nó như MyClass.LAMBDA(). Nhưng hãy xem, LAMBDA là một phương pháp thể hiện. Và bạn đang gọi nó mà không có một ví dụ thực tế tại chỗ.

Chính xác thì bạn đang cố gắng làm gì?

Tôi cho rằng, nếu bạn đặt tên cho cấu trúc lambda, bạn cũng có thể khai báo nó theo cách 'bình thường' - def. Từ kinh nghiệm của tôi, chỉ có một vài trường hợp biệt lập khi sử dụng lambas thực sự góp phần vào chất lượng mã.

+0

LAMBDA là thành viên * * nếu được định nghĩa như vậy. Đừng để các 'lambda' phân tâm bạn. Hãy xem xét 'LAMBDA = 4'. – kennytm

+0

bah, thiếu 'return' là một sự xấu hổ thực sự – shylent

+2

@KennyTM," thành viên lớp học "không phải là thuật ngữ Python, vì vậy nó có vẻ giống như một nền tảng kỳ lạ để chọn nitpick. Khi shylent nói đó là một phương pháp, ông có nghĩa là nó như chúng tôi liên tục làm: ông nói về điều ngữ nghĩa, không phải là tên. –

2

LAMBDA đây chỉ là một phương pháp bình thường. Khi bạn nhìn lên lớp, bạn sẽ có được phương thức không bị ràng buộc , đó là một điều ngớ ngẩn có chức năng của bạn và áp đặt điều đó - mặc dù self vẫn chưa được thông qua - đối số đầu tiên cho nó phải là một ví dụ của lớp được đề cập.

Để nhắc lại, LAMBDA = lambda: MyClass.ClassMethod() không khác biệt bất kỳ là def LAMBDA(): return MyClass.ClassMethod(). Trong trường hợp sau, rõ ràng hơn là bạn có định nghĩa phương thức bị hỏng. Hàm lambda và hàm def tạo thành cùng một kiểu đối tượng chính xác, và Python biến chúng thành các phương thức có cùng quy tắc on-the-fly tại thời gian tra cứu.

tôi nghi ngờ mã bạn có thể muốn là

class MyClass(object): 
    @classmethod 
    def ClassMethod(cls): 
     pass 
MyClass.LAMBDA = MyClass.ClassMethod 

hoặc

class MyClass(object): 
    @classmethod 
    def ClassMethod(cls): 
     pass 

    @classmethod 
    def LAMBDA(cls): 
     return cls.ClassMethod() 

(Lưu ý cuối cùng này có thể được viết với một lambda như bạn ban đầu đã làm, nhưng không có lý do gì để. Tôi sẽ không bao giờ sử dụng = lambda trong bất kỳ mã nào của tôi, cá nhân. Ngoài ra, hãy lưu ý rằng ClassMethodLAMBDA không tuân thủ các quy tắc về cách viết hoa bình thường của Python.)

0

Tôi cần một số thuộc tính lớp được điền bởi lambda đó và tự tham chiếu lớp đó rõ ràng là không thể ở giai đoạn đó.

Nhưng từ mã cho bạn, tất cả LAMBDA sẽ làm gì khi nó được gọi là chính nó gọi MyClass.ClassMethod(), có nghĩa là phương pháp làm populating là ClassMethod (điều này là, tất nhiên, giả định rằng cơ thể của ClassMethod không phải là thực sự duy nhất pass mà bạn đã thể hiện, bởi vì nếu sau đó thực hiện tất cả điều này là một bài tập trong vô ích).Trừ khi có một số khía cạnh của mã của bạn ngăn cản bạn tham chiếu đến lớp trước khi sử dụng nó cho bất cứ điều gì, tại sao bạn không thể gọi MyClass.ClassMethod() sau khi định nghĩa lớp học?

Và nếu bạn đang cố gắng sửa đổi thuộc tính của lớp bên trong định nghĩa (nghĩa là gọi LAMBDA trong định nghĩa của MyClass, bên ngoài bất kỳ phương thức/chức năng nào), bạn có thể muốn xem phần tài liệu về số metaclasses.

Trên một lưu ý phụ, nếu bạn muốn gán thuộc tính cho một lớp, bạn thậm chí không cần phải làm như vậy trong nội dung của lớp đó.

>>> class cls(object): # or just "class cls:" 
...  pass 
... 
>>> cls.value = 10 
>>> cls.name = 'class' 
>>> cls.value 
10 
>>> cls.name 
'class' 
>>> dir(cls) 
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', 
'__getattribute__', '__hash__', '__init__', '__module__', '__new__', 
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', 
'__str__', '__subclasshook__', '__weakref__', 'name', 'value'] 
1

Có một giải pháp trực tiếp khác cho việc này. Có lẽ đây không phải là điều sạch nhất, nhưng tôi nghĩ đó là những gì bạn đang thắc mắc. Tôi chỉ chạy vào một tình huống tương tự. Bạn có thể hủy cố ý nó với staticmethod().

Dưới đây là phiên bản có sai sót:

def bar(): return 0 

class foo(object): 
    x = lambda:bar() 
    @classmethod 
    def grok(klass): 
    return klass.x() 

foo().grok() 

Traceback (most recent call last): 
    File "<console>", line 1, in <module> 
    File "<console>", line 4, in grok 
TypeError: unbound method <lambda>() must be called with foo instance as first argument (got nothing instead) 

Và phiên bản điều chỉnh nhẹ:

def bar(): return 0 

class foo(object): 
    x = staticmethod(lambda:bar()) 
    @classmethod 
    def grok(klass): 
    return klass.x() 

foo().grok() 

0 

Lưu ý rằng cả hai bên trên cũng xảy ra đối với:

x = bar 

Thay vào đó. Tôi đã chỉ bao gồm các lambda là một phản ứng trực tiếp cho câu hỏi. Tất cả các đề xuất trên cũng hoạt động, đây chỉ là cách trực tiếp để thay đổi mã càng ít càng tốt.

Đối với lý do tại sao người ta lại muốn làm điều gì đó giống như công việc trên với lambda? Trong trường hợp của tôi, tôi đã làm một lớp nhà máy có bộ xử lý sự kiện thỉnh thoảng sẽ sử dụng dữ liệu trên toàn lớp để lấy thông tin, và một số thông tin đó có tính chất giá trị hoặc có thể gọi được. Vì vậy, "callable" là một lambda thẳng tay của người sử dụng, mà phải được gọi với self.value() hoặc klass.value() nhưng value là một chức năng unbound (lambda hoặc cách khác).

Các vấn đề liên quan