2010-07-30 36 views
12

Ý kiến ​​của người dân về việc sử dụng __call__ là gì. Tôi chỉ rất hiếm khi nhìn thấy nó được sử dụng, nhưng tôi nghĩ rằng đó là một công cụ rất tiện dụng để sử dụng khi bạn biết rằng một lớp sẽ được sử dụng cho một số hành vi mặc định.Khi nào sử dụng __call__ một ý tưởng hay?

+1

-1: Đây không phải là câu hỏi "ý kiến". Nó không phải là "tiện dụng" cho mọi thứ. Nó chỉ đơn giản là ** bắt buộc ** để tạo ** đối tượng có thể gọi **. –

+0

Câu hỏi tập trung hơn vào thời điểm có lợi khi có đối tượng có thể gọi được. Phương pháp '__call__' đơn giản là phương tiện để đạt được điều đó. Tôi quan tâm nhiều đến hành vi hơn là cơ chế đạt được hành vi. Nếu bạn muốn bỏ phiếu cho câu hỏi, bạn nên làm điều đó với nút mũi tên, thay vì bình luận của bạn. –

+1

Nó thường được coi là lịch sự để chỉ ra thông qua bình luận tại sao một bài đăng đã được bỏ phiếu xuống và nếu bài viết có thể được cải thiện. Giả sử bình luận được thực hiện _politely_, tất nhiên. –

Trả lời

15

Tôi nghĩ trực giác của bạn là đúng.

Trước đây, các đối tượng có thể gọi (hoặc những gì tôi đôi khi được gọi là "functors") đã được sử dụng trong thế giới OO để mô phỏng các bao đóng. Trong C++ chúng thường xuyên không thể thiếu.

Tuy nhiên, __call__ có khá nhiều đối thủ cạnh tranh trong thế giới Python:

  • Một tên phương pháp thông thường, mà hành vi đôi khi có thể có rất nhiều cách dễ dàng hơn rút ra từ tên. Có thể chuyển đổi thành một phương thức bị ràng buộc, có thể được gọi là một hàm.
  • Một đóng cửa, thu được bằng cách trả về một hàm được xác định trong một khối lồng nhau.
  • Một lambda, một cách hạn chế nhưng nhanh chóng để đóng cửa.
  • Máy phát điện và coroutines, có cơ quan giữ trạng thái tích lũy giống như một functor có thể.

Tôi muốn nói thời gian sử dụng __call__ là khi bạn không được phục vụ tốt hơn theo một trong các tùy chọn ở trên. Kiểm tra các tiêu chí sau, có thể:

  • Đối tượng của bạn có trạng thái.
  • Có một hành vi "chính" rõ ràng đối với lớp học của bạn thật ngớ ngẩn khi đặt tên. Ví dụ.nếu bạn thấy mình viết run() hoặc doStuff() hoặc go() hoặc doRun() chưa từng có và phổ biến, bạn có thể có một ứng cử viên.
  • Đối tượng của bạn có trạng thái vượt quá mức mong đợi của chức năng của trình tạo.
  • Đối tượng của bạn kết thúc tốt đẹp, mô phỏng hoặc tóm tắt khái niệm về hàm.
  • Đối tượng của bạn có các phương pháp trợ giúp khác về mặt khái niệm thuộc về hành vi chính của bạn.

Một ví dụ tôi thích là đối tượng lệnh giao diện người dùng. Được thiết kế sao cho nhiệm vụ chính của họ là thực thi comnand, nhưng với các phương thức bổ sung để kiểm soát hiển thị của chúng như một mục menu, ví dụ, điều này dường như là một thứ bạn vẫn muốn một đối tượng có thể gọi được.

4

Sử dụng nó nếu bạn cần đối tượng của bạn để có thể gọi, đó là những gì nó có cho

Tôi không chắc chắn những gì bạn có nghĩa là bởi hành vi mặc định

Một nơi tôi đã tìm thấy nó đặc biệt hữu ích là khi sử dụng một wrapper hoặc somesuch nơi đối tượng được gọi sâu bên trong một số khung/thư viện.

+0

Urgh. Câu hỏi có vẻ thực sự ngớ ngẩn bây giờ. Theo hành vi mặc định, tôi có nghĩa là trong khi các lớp thường có nhiều phương thức, thường có một luồng công việc rất thường xuyên từ dữ liệu vào dữ liệu. Tôi đã tự hỏi nếu '__call__' có thể được sử dụng để tăng tốc độ truy cập vào luồng công việc chuẩn đó. –

+0

Vâng một chút. Tôi không biết chính xác những gì bạn có ý nghĩa với "tăng tốc độ truy cập vào quy trình công việc chuẩn" đó. '__call__' nói chung không có gì liên quan đến tốc độ. Bạn có thể lưu một tra cứu thuộc tính nếu bạn sử dụng 'obj()' thay vì một cái gì đó như 'obj.function_name()' nhưng điều đó không đáng nhắc đến. – nils

+0

@Tim McNamara: Đúng. Câu hỏi là ngớ ngẩn. Đặc biệt là phần "ý kiến" của nó. –

1

Nói chung, Python có một số phương pháp đôi gạch dưới. Họ đang có một lý do: họ là cách Python của các nhà khai thác quá tải. Ví dụ, nếu bạn muốn một lớp mới, trong đó bổ sung, tôi không biết, in "foo", bạn xác định các phương thức __add____radd__. Không có gì tốt hay xấu về điều này, hơn bất kỳ điều gì tốt hay xấu về việc sử dụng vòng lặp for.

Thực tế, sử dụng __call__ thường là cách tiếp cận nhiều hơn về Pythonic, vì nó khuyến khích sự rõ ràng của mã. Bạn có thể thay thế MyCalculator.calculateValues(foo) bằng số MyCalculator(foo).

+0

Có phải MyCalculator (foo) hoặc theCalculatorObject (foo) không? – Nabin

0

Thường được sử dụng khi lớp được sử dụng làm hàm với một số ngữ cảnh ví dụ, như một số DecoratorClass sẽ được sử dụng như @DecoratorClass('some param'), vì vậy 'một số thông số' sẽ được lưu trữ trong không gian tên của cá thể và sau đó được gọi là trang trí thực tế. Nó không phải là rất hữu ích khi lớp học của bạn cung cấp một số phương pháp khác nhau, vì nó thường không rõ ràng những gì sẽ gọi làm, và rõ ràng là tốt hơn so với tiềm ẩn trong những trường hợp này.

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