2012-10-25 27 views
19

Tôi đang nói chủ yếu về Python ở đây, nhưng tôi cho rằng điều này có thể giữ cho hầu hết các ngôn ngữ. Nếu tôi có một đối tượng có thể thay đổi được, đó là một ý tưởng tồi để thực hiện một phép toán tại chỗ cũng trả về đối tượng? Dường như hầu hết các ví dụ chỉ sửa đổi đối tượng và trả về None. Ví dụ: list.sort.Việc thực hiện các phép toán tại chỗ có trả lại đối tượng một ý tưởng tồi không?

+0

Tôi nghĩ đó là tất cả về sự nhất quán. Python khá nhất quán về các phương thức trên các đối tượng có thể thay đổi được các hoạt động tại chỗ. Miễn là bạn nhất quán về nó, không nên có một vấn đề với các hoạt động tại chỗ trả về một đối tượng hoặc đối tượng tham chiếu. –

+0

Nhưng tại sao lại như vậy ngay từ đầu? – asmeurer

+2

Tôi không chắc chắn 100%, nhưng hầu hết thời gian, không cần thao tác tại chỗ để trả về một đối tượng. Bạn không tạo ra một đối tượng mới mà cần phải được giao, sau khi tất cả. Ngoài ra, có tương tự với từng hoạt động tại chỗ để làm cho thực tế là bạn đang quay trở lại một cái gì đó để làm các hoạt động thêm vào nó rõ ràng rõ ràng. (ví dụ 'list.sort' so với' được sắp xếp (danh sách) ',' list.reverse' và 'đảo ngược (danh sách)') –

Trả lời

25

Vâng, đó là một ý tưởng tồi. Lý do là nếu các hoạt động tại chỗ và không tại chỗ có kết quả giống hệt nhau, thì các lập trình viên sẽ thường xuyên kết hợp các hoạt động tại chỗ và các hoạt động không tại chỗ (List.sort()sorted()) và kết quả là khó -xảy ra lỗi.

Hoạt động tại chỗ tự quay lại có thể cho phép bạn thực hiện "chuỗi phương pháp", tuy nhiên, đây là thực hành không tốt vì bạn có thể vô tình bị tác dụng phụ ở giữa chuỗi.

Để ngăn chặn các lỗi như thế này, chuỗi phương pháp chỉ nên có một phương pháp có tác dụng phụ và chức năng đó phải ở cuối chuỗi. Các hàm trước đó trong chuỗi sẽ biến đổi đầu vào mà không có tác dụng phụ (ví dụ, điều hướng một cây, cắt một chuỗi, v.v.). Nếu các hoạt động tại chỗ tự trả về thì một lập trình viên bị ràng buộc vô tình sử dụng nó thay cho một hàm thay thế trả về một bản sao và do đó không có tác dụng phụ (một lần nữa, List.sort()sorted()) có thể gây ra lỗi gỡ lỗi.

Đây là lý do hàm thư viện chuẩn của Python luôn trả về bản sao hoặc trả về None và sửa đổi đối tượng tại chỗ, nhưng không bao giờ sửa đổi đối tượng tại chỗ và cũng tự trả về. Các thư viện Python khác như Django cũng theo thực hành này (xem this very similar question về Django).

+0

Đồng ý như một quy tắc chung, nhưng tôi nghĩ rằng có những ngoại lệ trong một số trường hợp cụ thể, mà không phải là quá hiếm. Ví dụ 1: Khi ngữ nghĩa của phương thức này rõ ràng là một hoạt động tại chỗ, giống như '.empty()' của jQuery. Eg2: Khi API được sử dụng phổ biến đến nỗi mọi người đều biết nó từ lần đầu tiên bắt đầu và không có phiên bản nào trả về một bản sao, như là '.append()' –

+0

Chỉ vì tên phương thức là một động từ hiện tại, không có nghĩa là mọi người sẽ thấy rõ rằng hoạt động này diễn ra tại chỗ. Phải mất một thời gian dài sau khi học Python trước khi tôi luôn nhớ rằng 'list.sort' đã diễn ra tại chỗ, mặc dù tên nghe có vẻ như nó nên làm điều đó. – asmeurer

+0

Không còn sự nhầm lẫn với việc kết thúc một chuỗi với một hoạt động tại chỗ? 'a.sort()' và 'a [: 2] .sort()' sẽ làm những việc hoàn toàn khác nhau (tôi đoán nó sẽ khác nếu bạn sử dụng một cái gì đó như một mảng 'sumpy', sử dụng các khung nhìn). Có lẽ vấn đề là 'sort' trở về' None' bảo vệ bạn khỏi suy nghĩ rằng 'a [: 2] .sort()' có ích gì không? – asmeurer

0

Tôi cho rằng nó phụ thuộc vào trường hợp sử dụng. Tôi không thấy lý do tại sao việc trả lại một vật thể từ một chiến dịch tại chỗ sẽ bị tổn thương, ngoài việc có thể bạn sẽ không sử dụng kết quả, nhưng đó không thực sự là vấn đề nếu bạn không siêu khó tính về chức năng thuần túy. Tôi thích mô hình chuỗi cuộc gọi, như sử dụng jQuery, vì vậy tôi đánh giá cao nó khi các hàm trả về đối tượng mà chúng đã hành động, trong trường hợp tôi muốn sử dụng nó hơn nữa.

8

Trả về đối tượng đã sửa đổi từ phương pháp đã sửa đổi nó có thể có một số lợi ích, nhưng không được đề xuất trong Python. Trả lại self sau khi thao tác sửa đổi sẽ cho phép bạn thực hiện method chaining trên đối tượng, đây là một cách thuận tiện để thực hiện một số phương thức trên cùng một đối tượng, đó là thành ngữ rất phổ biến trong lập trình hướng đối tượng. Và lần lượt, phương pháp chuỗi cho phép thực hiện đơn giản fluent interfaces. Ngoài ra, nó cho phép một số thành ngữ lập trình chức năng được thể hiện dễ dàng hơn.

Để đặt tên một vài ví dụ: bằng Python, thư viện Moka sử dụng phương pháp ghép chuỗi. Trong Java, lớp StringBuilder cho phép nhiều lời gọi append() trên cùng một đối tượng. Trong JavaScript, JQuery sử dụng phương pháp chuỗi rộng rãi. Smalltalk đưa ý tưởng này lên cấp độ tiếp theo: theo mặc định, tất cả các phương thức trả lại self trừ khi được chỉ định khác (do đó, phương pháp khuyến khích chuỗi) - tương phản với Python, trả về None theo mặc định.

Việc sử dụng thành ngữ này không phổ biến trong Python, bởi vì Python tuân theo Command/Query Separation Principle, cho biết "mọi phương thức phải là lệnh thực hiện tác vụ hoặc truy vấn trả về dữ liệu cho người gọi, nhưng không cả hai ".

Mọi thứ được xem xét, cho dù đó là ý tưởng tốt hay xấu để trả lại self ở cuối là vấn đề về văn hóa và quy ước lập trình, được trộn lẫn với sở thích cá nhân. Như đã đề cập ở trên, một số ngôn ngữ lập trình khuyến khích điều này (như Smalltalk) trong khi những ngôn ngữ khác không khuyến khích nó (như Python). Mỗi quan điểm đều có ưu điểm và nhược điểm, mở ra cho các cuộc thảo luận nóng. Nếu bạn là một người theo sách Python, bạn nên tránh trả lại self - hãy lưu ý rằng đôi khi có thể hữu ích khi vi phạm quy tắc này.

+1

Cảm ơn câu trả lời xuất sắc, đặc biệt là liên kết đến Nguyên tắc Tách biệt Truy vấn/Lệnh, giúp tôi đính kèm một nhãn cho một số thương mại thiết kế-off tôi đã được nghiền ngẫm trong thời gian gần đây. – FMc

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