Bạn có sử dụng mẫu get / set (bằng Python) không?


82

Sử dụng get / set dường như là một thực tế phổ biến trong Java (vì nhiều lý do khác nhau), nhưng tôi hầu như không thấy mã Python sử dụng điều này.

Tại sao bạn sử dụng hoặc tránh các phương thức get / set trong Python?


Tạo phản hồi từ mọi người. Phải thừa nhận rằng câu hỏi này là một phần của câu hỏi này là một phần của câu hỏi stackoverflow.com/questions/1022970/… tuy nhiên, có vẻ như tôi đã bị đột kích bởi một đám đông người đang nhìn nó từ góc độ chữ "J". Cảm ơn một lần nữa cho việc khôi phục niềm tin của tôi trong sự tỉnh táo ...
Avery Payne

1
Bối cảnh là quan trọng, và ở đây Python và Java chỉ đơn giản là khác nhau. (Tuy nhiên, tôi loại bỏ Python từ tiêu đề vì chúng tôi sử dụng thẻ cho rằng trên SO;.)

Câu trả lời:


59

Liên kết thú vị: Python không phải là Java :)

Trong Java, bạn phải sử dụng getters và setters vì việc sử dụng các trường công khai sẽ không cho bạn cơ hội quay lại và thay đổi quyết định sau này sang sử dụng getters và setters. Vì vậy, trong Java, bạn cũng có thể giải quyết được việc vặt từ phía trước. Trong Python, điều này thật ngớ ngẩn, bởi vì bạn có thể bắt đầu với một thuộc tính bình thường và thay đổi ý định bất cứ lúc nào mà không ảnh hưởng đến bất kỳ ứng dụng khách nào của lớp. Vì vậy, đừng viết getters và setters.


3
cộng với setters / getters làm tăng thêm chi phí hiệu suất, đặc biệt là trong Python.
Nick Dandoulakis

4
Đây không đặt một gánh nặng gia tăng đối với các nhà thiết kế đẳng cấp, trong đó các biến dụ ngầm trở thành một phần của API công cộng của lớp. Khi thiết lập một lớp, hãy suy nghĩ rõ ràng về những biến cá thể nào bạn muốn được truy cập từ bên ngoài so với những biến thực sự chỉ là một phần của việc triển khai lớp của bạn. Đặt tiền tố cho các triển khai nội bộ bằng dấu '_' ở đầu. Đây là dấu hiệu cảnh báo Python rằng nếu việc triển khai thay đổi, biến này cũng có thể thay đổi hoặc thậm chí biến mất hoàn toàn. Nếu không, bạn sẽ thấy kiến ​​thức triển khai bị rò rỉ ra khỏi lớp học của mình, khiến bạn khó thay đổi sau này.
PaulMcG

8
@Nick D: Tôi không nghĩ trình truy cập là nơi thích hợp để thực hiện tối ưu hóa tốc độ trong Python.
wRAR

1
@Nick D: Ý tôi là, đó là một ngôn ngữ thông dịch khuyến khích khả năng đọc chứ không phải hiệu suất, vì vậy sẽ có nhiều nơi tốt hơn để tối ưu hóa trong một chương trình.
wRAR

2
@Paul: Nó không phải là một thuộc tính nội bộ trừ khi nó được đặt tên bằng một hoặc hai dấu gạch dưới ở đầu (với dạng đầu tiên thường được ưu tiên hơn dạng sau có tên khác thường của Python). Nếu bạn không muốn viết tài liệu và vấn đề này làm phiền bạn, chỉ cần sử dụng _name theo mặc định cho tất cả các thuộc tính phiên bản.

113

Trong python, bạn chỉ có thể truy cập trực tiếp thuộc tính vì nó là công khai:

class MyClass:

    def __init__(self):
        self.my_attribute = 0  

my_object = MyClass()
my_object.my_attribute = 1 # etc.

Nếu bạn muốn thực hiện điều gì đó trên quyền truy cập hoặc đột biến của thuộc tính, bạn có thể sử dụng các thuộc tính :

class MyClass:

    def __init__(self):
        self._my_attribute = 0

    @property
    def my_attribute(self):
        # Do something if you want
        return self._my_attribute

    @my_attribute.setter
    def my_attribute(self, value):
        # Do something if you want
        self._my_attribute = value

Điều quan trọng, mã khách hàng vẫn được giữ nguyên.


30

Đây là những gì Guido van Rossum nói về điều đó trong Masterminds of Programming

Ý bạn là gì khi "chống lại ngôn ngữ"?

Guido: Điều đó thường có nghĩa là họ đang cố gắng tiếp tục những thói quen đã hoạt động tốt với một ngôn ngữ khác.

[...] Mọi người sẽ biến mọi thứ thành một lớp và biến mọi truy cập thành một phương thức truy cập,
nơi đó thực sự không phải là một điều khôn ngoan để làm trong Python; bạn sẽ có nhiều mã dài dòng
hơn, khó gỡ lỗi hơn và chạy chậm hơn rất nhiều. Bạn biết cụm từ "Bạn có thể viết FORTRAN bằng bất kỳ ngôn ngữ nào?" Bạn cũng có thể viết Java bằng bất kỳ ngôn ngữ nào.


14

Không, nó không có nghĩa. Cách thường được chấp nhận là sử dụng thuộc tính dữ liệu bình thường và thay thế những thuộc tính cần logic get / set phức tạp hơn bằng thuộc tính.


13
+1: "Chúng tôi đều là người lớn ở đây". Mã hiển thị. "private" và "getter / setter" không tạo ra bất kỳ giá trị nào khi tất cả mã có thể được nhìn thấy.
S.Lott

7

Câu trả lời ngắn gọn cho câu hỏi của bạn là không, bạn nên sử dụng thuộc tính khi cần thiết. Ryan Tamyoko đưa ra câu trả lời dài trong bài viết Getters / Setters / Fuxors của anh ấy

Giá trị cơ bản của tất cả những điều này là bạn muốn cố gắng đảm bảo rằng mỗi dòng mã đơn lẻ đều có giá trị hoặc ý nghĩa nào đó đối với lập trình viên. Ngôn ngữ lập trình dành cho con người, không phải máy móc. Nếu bạn có mã trông giống như nó không có ích gì, khó đọc hoặc có vẻ tẻ nhạt, thì rất có thể Python có một số tính năng ngôn ngữ cho phép bạn xóa nó.


5

Quan sát của bạn là đúng. Đây không phải là một phong cách lập trình Python thông thường. Tất cả các thuộc tính đều là công khai, vì vậy bạn chỉ cần truy cập (lấy, đặt, xóa) chúng như cách bạn làm với các thuộc tính của bất kỳ đối tượng nào có chúng (không chỉ các lớp hoặc cá thể). Thật dễ dàng để biết khi nào các lập trình viên Java học Python vì mã Python của họ trông giống như Java sử dụng cú pháp Python!

Tôi chắc chắn đồng ý với tất cả các áp phích trước đó, đặc biệt là liên kết của @ Maximiliano đến bài báo nổi tiếng của Phillip đề xuất của @ Max rằng bất kỳ thứ gì phức tạp hơn cách tiêu chuẩn để thiết lập (và nhận) các thuộc tính lớp và phiên bản là sử dụng Thuộc tính (hoặc Bộ mô tả để tổng quát hơn) để tùy chỉnh việc nhận và thiết lập các thuộc tính! (Điều này bao gồm việc có thể thêm các phiên bản tùy chỉnh của riêng bạn của chính sách riêng tư, được bảo vệ, bạn bè hoặc bất kỳ chính sách nào bạn muốn nếu bạn muốn một cái gì đó khác với công khai.)

Như một bản trình diễn thú vị, trong Lập trình Python lõi (chương 13, mục 13.16), tôi đã đưa ra một ví dụ về việc sử dụng bộ mô tả để lưu trữ các thuộc tính vào đĩa thay vì trong bộ nhớ !! Vâng, đó là một hình thức kỳ lạ của lưu trữ liên tục, nhưng nó làm cho bạn thấy một ví dụ về những gì có thể!

Đây là một bài đăng liên quan khác mà bạn có thể thấy hữu ích: Python: nhiều thuộc tính, một setter / getter


0

Tôi đã đến đây cho câu trả lời đó (tiếc là tôi không thể). Nhưng tôi đã tìm thấy một tác phẩm xung quanh nơi khác. Mã bên dưới này có thể thay thế cho get .
class get_var_lis: def __init__(self): pass def __call__(self): return [2,3,4] def __iter__(self): return iter([2,3,4]) some_other_var = get_var_lis
Đây chỉ là một cách giải quyết . Bằng cách sử dụng khái niệm trên, bạn cũng có thể dễ dàng xây dựng phương pháp get / set trong py.


-10

Giáo viên của chúng tôi đã đưa ra một ví dụ trên lớp giải thích khi nào chúng ta nên sử dụng các hàm truy cập.

class Woman(Human):
    def getAge(self):
        if self.age > 30:
            return super().getAge() - 10
        else:
            return super().getAge()

Tôi không đưa cho bạn phiếu phản đối, nhưng tôi nghĩ mình sẽ đồng ý. Điểm của cuộc thảo luận là "tại sao chúng ta cần get () / set () để truy cập thuộc tính trực tiếp bằng Python". Trong Java, có ngôn ngữ ... các tính năng ... làm cho điều này trở nên đáng mơ ước. Trong Python, không quá nhiều.
Avery Payne

7
Ngoài việc không thực sự trả lời câu hỏi, ví dụ được sử dụng trong câu trả lời này là xúc phạm. Tuyên bố rằng giáo viên của bạn đã sử dụng nó không biện minh cho sự phân biệt giới tính của nó.
Touzen

Tôi nghi ngờ điều này cho thấy sự phân biệt giới tính, đơn thuần là sự ngây thơ của bạn. Ở thế hệ của bà tôi, nhiều phụ nữ nói đùa rằng tuổi của họ trẻ hơn thực tế vài tuổi. Ngoài ra nó không có gì để làm với câu trả lời dù sao.
Johan Snowgoose
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.