2009-11-10 24 views
17

tôi đã viết mã như thế nàyIssue với việc đối tượng có thể được gọi trong python

>>> class a(object): 
     def __init__(self): 
      self.__call__ = lambda x:x 

>>> b = a() 

tôi mong đợi rằng đối tượng của lớp một nên đối tượng callable nhưng cuối cùng nó không phải là.

>>> b() 

Traceback (most recent call last): 
    File "<pyshell#5>", line 1, in <module> 
     b() 
TypeError: 'a' object is not callable 
>>> callable(b) 
False 

>>> hasattr(b,'__call__') 
True 
>>> 

Tôi không hiểu tại sao. Xin hãy giúp tôi.

+0

Tôi đang cố gắng để làm cho một số đường syntatic. Bạn có thể tưởng tượng tạo ra một bộ tạo hàm động như thế này. lớp A: b = create_custom_function ("AA") c = create_custom_function ("BB") – kjshim

Trả lời

16

Sp phương pháp sinh thái được nhìn lên trên loại (ví dụ: lớp học) của đối tượng đang được vận hành, chứ không phải trên trường hợp cụ thể. Hãy suy nghĩ về nó: nếu không, nếu một lớp định nghĩa __call__ ví dụ, khi lớp học được gọi là __call__ nên được gọi là ... một thảm họa! Nhưng may mắn thay, phương pháp đặc biệt thay vào đó là nhìn lên loại của lớp học, siêu thi AKA, và tất cả đều tốt ("các lớp kế thừa" có hành vi rất bất thường trong điều này, đó là lý do tại sao chúng ta tốt hơn với những kiểu mới - đó là những cái duy nhất còn lại trong Python 3).

Vì vậy, nếu bạn cần "ghi đè mỗi thể hiện" các phương pháp đặc biệt, bạn phải đảm bảo cá thể có lớp duy nhất của riêng nó. Điều đó rất dễ dàng:

class a(object): 
    def __init__(self): 
     self.__class__ = type(self.__class__.__name__, (self.__class__,), {}) 
     self.__class__.__call__ = lambda x:x 

và bạn đang ở đó. Tất nhiên điều đó sẽ là ngớ ngẩn trong trường hợp này, vì mỗi trường hợp kết thúc với cùng một "cái gọi là một ví dụ" (!) __call__, nhưng nó sẽ hữu ích nếu bạn thực sự cần ghi đè trên cơ sở từng cá thể .

+0

Wow! Đó là vấn đề giữa phương pháp mới và kiểu cũ. Cảm ơn bạn vì cách thông minh để ghi đè rằng – kjshim

+0

@kjshim, bạn được chào đón, nhưng nó không đặc biệt thông minh, chỉ là cách Python chuẩn để làm điều đó ;-). –

12

__call__ cần phải được xác định trên lớp, không phải là ví dụ

class a(object): 
    def __init__(self): 
     pass 
    __call__ = lambda x:x 

nhưng hầu hết mọi người có thể tìm thấy nó dễ đọc hơn để xác định phương pháp theo cách thông thường

class a(object): 
    def __init__(self): 
     pass 
    def __call__(self): 
     return self 

Nếu bạn cần phải có hành vi khác nhau cho từng trường hợp bạn có thể thực hiện như thế này

class a(object): 
    def __init__(self): 
     self.myfunc = lambda x:x 

    def __call__(self): 
     return self.myfunc(self) 
+0

Điều gì sẽ xảy ra nếu tôi muốn tạo một hàm có thể gọi riêng biệt trong thời gian chạy? Bạn có thể cho tôi một cách dễ hiểu không? Cảm ơn bạn đã trả lời. – kjshim

+0

và, tôi đã tham khảo bài viết này http://code.activestate.com/recipes/52304/ – kjshim

1

Điều này thì sao? Xác định một AllowDynamicCall lớp cơ sở:

class AllowDynamicCall(object): 
    def __call__(self, *args, **kwargs): 
     return self._callfunc(self, *args, **kwargs) 

Và sau đó phân lớp AllowDynamicCall:

class Example(AllowDynamicCall): 
    def __init__(self): 
     self._callfunc = lambda s: s 
Các vấn đề liên quan