Thuộc tính lớp truy cập Python

Gần đây tôi đã xem mã nguồn của ứng dụng GUI dựa trên wxPython, khoảng 45. Kích thước 5KLOC, không tính các thư viện được sử dụng [e. g. xoắn]. Đoạn mã này được viết bởi các nhà phát triển Java, những người còn khá mới đối với Python và nó bị một số lỗi.

Điều đó đã được viết hơn 16 năm trước và nó vẫn đúng. Cách
Pythonic nhất để viết lớp ví dụ của bạn là.

class Student:
    def __init__[self]:
        self.permission = False
    def go_to_party[self]:
        if self.permission:
            print["Let's party!"]
        else:
            print["I gotta study some more."]

Có bao nhiêu khả năng quyền đó sẽ thay đổi từ một cờ
cơ bản thành một triển khai phức tạp hơn? . Nhưng nếu có,
với các thuộc tính, chúng ta có thể thay đổi hoàn toàn cách triển khai mà không cần
thay đổi giao diện, điều không thể thực hiện dễ dàng hoặc hoàn toàn không
in Java.

Nhưng đừng viết tài sản đó ngay hôm nay, bởi vì bạn nghĩ rằng bạn có thể
cần nó trong sáu tháng nữa.

chim cút. com

bliki. Yagni

Yagni ["You Are't Gonna Need It"] là nguyên tắc chúng ta không nên xây dựng các tính năng giả định. Nó không nên được sử dụng như một sự biện minh cho việc bỏ qua chất lượng bên trong

[YAGNI không chỉ là lời khuyên tốt cho lập trình nhanh hoặc cực đoan. ]

Nếu bạn quyết định rằng bạn cần ẩn cờ quyền sau
thuộc tính, thì trong lớp, bạn có thể làm bất cứ điều gì mình muốn
. Nếu việc triển khai
is_permit phức tạp, thì tất nhiên, bạn sẽ ưu tiên viết mã
một lần bên trong thuộc tính và luôn sử dụng thuộc tính đó. Đừng
Lặp lại chính mình [DRY].

Nhưng đôi khi bạn có một trình thiết lập phức tạp và một trình nhận đơn giản
chỉ trả về giá trị của thuộc tính private.

@property
def permission[self]:
    return self._permission

@permitted.setter
def permission[self, value]:
    self._permission = something complicated

Tất nhiên bây giờ bạn nên sử dụng setter bên trong, DRY lại. Nhưng để
chỉ tìm nạp giá trị, bạn có thể sử dụng trường riêng tư thay vì
thuộc tính không? . Điều đó hoàn toàn phụ thuộc vào bạn. Đó là lớp học của bạn, tất nhiên bạn
có thể sử dụng nội bộ các trường riêng tư của lớp học.
cả hai đều có lợi thế và câu trả lời có thể sẽ phụ thuộc vào mức độ lớn và phức tạp của lớp
của bạn cũng như việc bạn có các lớp con hay không.

Truy cập trực tiếp vào thuộc tính private hiệu quả hơn một chút vì nó
tránh được chi phí hoạt động tra cứu thuộc tính và gọi phương thức.

Nhưng nó cũng có khớp nối bên trong cao hơn một chút. Nếu bộ thu thập
thay đổi, bây giờ bạn phải thay đổi bộ thu thập và tất cả các tham chiếu đến
thuộc tính nội bộ. Nếu thuộc tính bên trong thay đổi, bạn phải
thay đổi nó ở nhiều nơi.

Xin chào, @PedanticHacker

PedanticHacker

Vì vậy, nếu phiên bản được tạo trong một số mô-đun khác dưới dạng analysis = Analysis[], tôi nên thay đổi giá trị Boolean của thuộc tính phiên bản bằng cách thực hiện

@property
def permission[self]:
    return self._permission

@permitted.setter
def permission[self, value]:
    self._permission = something complicated
0 và kiểm tra giá trị của nó bằng cách thực hiện
@property
def permission[self]:
    return self._permission

@permitted.setter
def permission[self, value]:
    self._permission = something complicated
1?

Không, tôi sẽ nói, thiết kế như vậy là … xấu xí.

steven. daprano

Hầu hết Pythonic là chỉ sử dụng thuộc tính công khai, không có thuộc tính

Nhưng nếu bạn cần sử dụng các thuộc tính, thì sẽ có những ưu điểm và
bất lợi khi bỏ qua thuộc tính và sử dụng thuộc tính
riêng tư bên trong, vì vậy câu trả lời .

Vì vậy, cách dễ dàng và thiết thực nhất là truy cập vào chính

@property
def permission[self]:
    return self._permission

@permitted.setter
def permission[self, value]:
    self._permission = something complicated
2. Đơn giản,

class Analysis:
    def __init__[self]:
        self.enabled = False

Tôi sẽ làm thêm như sau [vì vậy bạn không phải lo lắng về ________ 10]

class Analysis:
    enabled = False
    def __init__[self]:
        self.enabled = False

Tôi nghĩ, cách an toàn nhưng hơi dư thừa có lẽ

class Analysis:
    def __init__[self]:
        self.__enabled = False
    
    def is_enabled[self]:
        return self.__enabled
    
    def enable[self, value]:
        self.__enabled = value
    
    @property
    def enabled[self]:
        return self.__enabled
    
    @enabled.setter
    def enabled[self, value]:
        self.__enabled = value

Ví dụ: gói GUI wxPython sử dụng cả hai kiểu [nhưng điều này có thể do lý do lịch sử và khả năng tương thích với wxWidgets]

>>> self.btn.Enabled
True
>>> self.btn.Enabled = False
>>> self.btn.IsEnabled[]
False
>>> self.btn.Enable[True]
True

Rốt cuộc,

câu trả lời phụ thuộc vào lớp học và sở thích của riêng bạn

Cảm ơn tất cả các bạn đã đóng góp cho cuộc thảo luận này với thông tin hữu ích.

Vui lòng cho phép tôi tóm tắt lại sự hiểu biết của tôi có được trong chủ đề thảo luận này

Tôi, với tư cách là nhà phát triển phần mềm, đang cố gắng tuân theo các phương pháp Python tuyệt đối tốt nhất, phải luôn truy cập và luôn sửa đổi trực tiếp các thuộc tính của phiên bản, không thông qua các phương thức getter và setter hoặc thông qua các thuộc tính getter và setter

Tôi chỉ cần xác định các thuộc tính getter [và, tùy thuộc vào cách sử dụng, cũng có thể là các thuộc tính setter] trong các phần đó của API có thể dễ bị thay đổi trong một thời gian không xác định trong tương lai để API của tôi có thể dễ dàng bảo trì

Nhưng tôi phải xác định thuộc tính getter [và, một lần nữa, tùy thuộc vào cách sử dụng, thuộc tính setter cũng có thể] nếu phải thực hiện một số phép tính đối với giá trị của thuộc tính thể hiện

Hơn nữa, giả sử rằng API của tôi cần một thuộc tính thể hiện ở chế độ chỉ đọc, tôi sẽ phải xác định thuộc tính getter cho thuộc tính thể hiện đó mà không xác định thuộc tính setter cho nó. [Đó là cách duy nhất trong Python để tạo thuộc tính cá thể chỉ đọc. ]

Ngoài ra, giả sử rằng tôi – vì một lý do nào đó – quyết định sẽ rất tuyệt nếu có một đối tượng kiểm tra giá trị Boolean của một thuộc tính thể hiện [với các đối tượng có tên là

@property
def permission[self]:
    return self._permission

@permitted.setter
def permission[self, value]:
    self._permission = something complicated
1,
@property
def permission[self]:
    return self._permission

@permitted.setter
def permission[self, value]:
    self._permission = something complicated
2, v.v. ], đối tượng sẽ phải được định nghĩa là một phương thức chứ không phải thuộc tính getter. Tuy nhiên, bất chấp sự cám dỗ mạnh mẽ nhất khi có một đối tượng như vậy, tôi luôn muốn kiểm tra trực tiếp giá trị của một thuộc tính thể hiện, không phải thông qua phương thức getter hoặc thông qua thuộc tính getter. [Nhưng nếu nhu cầu về một phương thức getter gián tiếp như vậy là hợp lý và hóa ra là giải pháp đơn giản nhất cho một vấn đề, thì phương thức getter luôn được sử dụng thay cho thuộc tính getter vì thuộc tính không thể đưa ra đối số trong khi phương thức có thể. ]

Chủ Đề