Con trăn setter là gì?

Nếu bạn đến từ một ngôn ngữ như Java hoặc C++, thì có lẽ bạn đã quen với việc viết các phương thức getter và setter cho mọi thuộc tính trong lớp của mình. Các phương pháp này cho phép bạn truy cập và thay đổi các thuộc tính riêng tư trong khi duy trì đóng gói. Trong Python, thông thường bạn sẽ hiển thị các thuộc tính như một phần của API công khai và sử dụng các thuộc tính khi bạn cần các thuộc tính có hành vi chức năng

Mặc dù các thuộc tính là cách sử dụng của Pythonic, nhưng chúng có thể có một số nhược điểm thực tế. Do đó, bạn sẽ tìm thấy một số tình huống trong đó getters và setters được ưu tiên hơn các thuộc tính

Trong hướng dẫn này, bạn sẽ

  • Viết các phương thức getter và setter trong các lớp học của bạn
  • Thay thế các phương thức getter và setter bằng các thuộc tính
  • Khám phá các công cụ khác để thay thế các phương thức getter và setter trong Python
  • Quyết định khi nào các phương thức setter và getter có thể là công cụ phù hợp cho công việc

Để tận dụng tối đa hướng dẫn này, bạn nên làm quen với lập trình hướng đối tượng Python. Nó cũng sẽ là một điểm cộng nếu bạn có kiến ​​thức cơ bản về các thuộc tính và bộ mô tả Python

Mã nguồn. Nhấp vào đây để lấy mã nguồn miễn phí chỉ cho bạn cách thức và thời điểm sử dụng getters, setters và thuộc tính trong Python

Làm quen với các phương thức Getter và Setter

Khi bạn định nghĩa một lớp trong lập trình hướng đối tượng (OOP), bạn có thể sẽ kết thúc với một số thuộc tính lớp và thể hiện. Các thuộc tính này chỉ là các biến mà bạn có thể truy cập thông qua cá thể, lớp hoặc cả hai

Các thuộc tính giữ trạng thái bên trong của các đối tượng. Trong nhiều trường hợp, bạn sẽ cần truy cập và thay đổi trạng thái này, bao gồm việc truy cập và thay đổi các thuộc tính. Thông thường, bạn sẽ có ít nhất hai cách để truy cập và thay đổi thuộc tính. bạn có thể

  1. Truy cập và thay đổi thuộc tính trực tiếp
  2. Sử dụng các phương thức để truy cập và thay đổi thuộc tính

Nếu bạn hiển thị các thuộc tính của một lớp cho người dùng của mình, thì các thuộc tính đó sẽ tự động trở thành một phần của API công khai của lớp đó. Chúng sẽ là các thuộc tính công khai, nghĩa là người dùng của bạn sẽ trực tiếp truy cập và thay đổi các thuộc tính trong mã của họ

Có một thuộc tính là một phần của API của lớp sẽ trở thành một vấn đề nếu bạn cần thay đổi cách triển khai nội bộ của chính thuộc tính đó. Một ví dụ rõ ràng về vấn đề này là khi bạn muốn biến thuộc tính được lưu trữ thành thuộc tính được tính toán. Một thuộc tính được lưu trữ sẽ ngay lập tức phản hồi các hoạt động truy cập và đột biến bằng cách chỉ truy xuất và lưu trữ dữ liệu, trong khi một thuộc tính được tính toán sẽ chạy các tính toán trước các hoạt động đó

Vấn đề với các thuộc tính thông thường là chúng không thể triển khai nội bộ vì chúng chỉ là các biến. Vì vậy, việc thay đổi cách triển khai bên trong của một thuộc tính sẽ yêu cầu chuyển đổi thuộc tính đó thành một phương thức, điều này có thể sẽ phá vỡ mã của người dùng của bạn. Tại sao?

Để xử lý loại vấn đề này, một số ngôn ngữ lập trình, như Java và C++, yêu cầu bạn cung cấp các phương thức để thao tác các thuộc tính của các lớp của bạn. Các phương thức này thường được gọi là phương thức getter và setter. Bạn cũng có thể thấy chúng được gọi là phương thức truy cập và biến đổi

Loại bỏ các quảng cáo

Phương thức Getter và Setter là gì?

Các phương thức getter và setter khá phổ biến trong nhiều ngôn ngữ lập trình hướng đối tượng. Vì vậy, rất có thể bạn đã nghe về chúng rồi. Như một định nghĩa sơ bộ, bạn có thể nói rằng getters và setters là

  • người bắt. Một phương thức cho phép bạn truy cập một thuộc tính trong một lớp nhất định
  • người định cư. Một phương thức cho phép bạn thiết lập hoặc thay đổi giá trị của một thuộc tính trong một lớp

Trong OOP, mẫu getter và setter gợi ý rằng các thuộc tính public chỉ nên được sử dụng khi bạn chắc chắn rằng không ai cần đính kèm hành vi với chúng. Nếu một thuộc tính có khả năng thay đổi cách triển khai bên trong của nó, thì bạn nên sử dụng các phương thức getter và setter

Việc triển khai mẫu getter và setter yêu cầu

  1. Làm cho các thuộc tính của bạn không công khai
  2. Viết các phương thức getter và setter cho từng thuộc tính

Ví dụ: giả sử bạn cần viết một lớp

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
0 với các thuộc tính văn bản và phông chữ. Nếu bạn sử dụng các phương thức getter và setter để quản lý các thuộc tính này, thì bạn sẽ viết lớp như trong đoạn mã sau

# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value

Trong ví dụ này, hàm tạo của

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
0 nhận hai đối số,
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
2 và
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
3. Các đối số này được lưu trữ trong các thuộc tính đối tượng không công khai của
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
4 và
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
5, tương ứng

Sau đó, bạn xác định các phương thức getter và setter cho cả hai thuộc tính. Thông thường, các phương thức getter trả về giá trị của thuộc tính đích, trong khi các phương thức setter lấy một giá trị mới và gán nó cho thuộc tính bên dưới

Ghi chú. Python không có khái niệm về các công cụ sửa đổi truy cập, chẳng hạn như

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
6,
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
7 và
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
8, để hạn chế quyền truy cập vào các thuộc tính và phương thức trong một lớp. Trong Python, sự khác biệt là giữa các thành viên lớp công khai và không công khai

Nếu bạn muốn báo hiệu rằng một thuộc tính hoặc phương thức nhất định là không công khai, thì bạn nên sử dụng quy ước Python đã được thiết lập tốt về việc thêm tiền tố vào tên bằng dấu gạch dưới (

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
9)

Lưu ý rằng đây chỉ là một quy ước. Nó không ngăn bạn và các lập trình viên khác truy cập các thuộc tính bằng cách sử dụng ký hiệu dấu chấm, như trong

# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
10. Tuy nhiên, đó là thực tế xấu để vi phạm quy ước này

Bạn có thể sử dụng lớp

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
0 của mình như trong các ví dụ bên dưới

>>>

# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
3

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
0 ẩn các thuộc tính của nó khỏi truy cập công khai và thay vào đó hiển thị các phương thức getter và setter. Bạn có thể sử dụng các phương thức này khi cần truy cập hoặc thay đổi các thuộc tính của lớp, thuộc tính không công khai và do đó không phải là một phần của API lớp, như bạn đã biết

Các phương thức Getter và Setter đến từ đâu?

Để hiểu các phương thức getter và setter đến từ đâu, hãy quay lại ví dụ

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
0 và nói rằng bạn muốn tự động lưu trữ văn bản của nhãn bằng chữ in hoa. Thật không may, bạn không thể đơn giản thêm hành vi này vào một thuộc tính thông thường như
# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
14. Bạn chỉ có thể thêm hành vi thông qua các phương thức, nhưng việc chuyển đổi một thuộc tính công khai thành một phương thức sẽ tạo ra một thay đổi lớn trong API của bạn

Vậy, bạn có thể làm gì? . Tuy nhiên, các ngôn ngữ lập trình như Java và C++ không hỗ trợ cấu trúc giống như thuộc tính hoặc thuộc tính của chúng không hoàn toàn giống thuộc tính của Python

Đó là lý do tại sao những ngôn ngữ này khuyến khích bạn không bao giờ để lộ các thuộc tính của mình như một phần của API công khai. Thay vào đó, bạn phải cung cấp các phương thức getter và setter, cung cấp một cách nhanh chóng để thay đổi cách triển khai nội bộ các thuộc tính của bạn mà không thay đổi API công khai của bạn

Đóng gói là một chủ đề cơ bản khác liên quan đến nguồn gốc của các phương thức getter và setter. Về cơ bản, nguyên tắc này đề cập đến việc kết hợp dữ liệu với các phương thức hoạt động trên dữ liệu đó. Bằng cách này, các hoạt động truy cập và đột biến sẽ được thực hiện thông qua các phương thức dành riêng

Nguyên tắc này cũng liên quan đến việc hạn chế quyền truy cập trực tiếp vào các thuộc tính của đối tượng, điều này sẽ ngăn việc tiết lộ chi tiết triển khai hoặc vi phạm tính bất biến của trạng thái

Để cung cấp cho

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
0 chức năng mới được yêu cầu trong Java hoặc C++, bạn phải sử dụng các phương thức getter và setter ngay từ đầu. Làm cách nào bạn có thể áp dụng mẫu getter và setter để giải quyết vấn đề trong Python?

Xem xét phiên bản sau của

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
0

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior

Trong phiên bản cập nhật này của

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
0, bạn cung cấp các phương thức getter và setter cho văn bản của nhãn. Thuộc tính giữ văn bản là không công khai vì nó có dấu gạch dưới ở đầu tên của nó,
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
4. Phương thức setter thực hiện chuyển đổi đầu vào, chuyển đổi văn bản thành chữ hoa

Bây giờ bạn có thể sử dụng lớp

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
0 của mình như trong đoạn mã sau

>>>

# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
1

Mát mẻ. Bạn đã thêm thành công hành vi bắt buộc vào thuộc tính văn bản của nhãn. Bây giờ phương thức setter của bạn có một mục tiêu thực sự thay vì chỉ gán một giá trị mới cho thuộc tính đích. Nó có mục tiêu thêm hành vi bổ sung vào thuộc tính

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
4

Mặc dù mẫu getter và setter khá phổ biến trong các ngôn ngữ lập trình khác, nhưng đó không phải là trường hợp trong Python

Việc thêm các phương thức getter và setter vào các lớp của bạn có thể làm tăng đáng kể số dòng trong mã của bạn. Getters và setters cũng tuân theo một mô hình lặp đi lặp lại và nhàm chán sẽ cần thêm thời gian để hoàn thành. Mẫu này có thể dễ bị lỗi và tẻ nhạt. Bạn cũng sẽ thấy rằng chức năng ngay lập tức thu được từ tất cả mã bổ sung này thường bằng không

Tất cả điều này nghe có vẻ giống như điều mà các nhà phát triển Python không muốn thực hiện trong mã của họ. Trong Python, có thể bạn sẽ viết lớp

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
0 như trong đoạn mã sau

>>>

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
6

Ở đây,

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
62 và
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
63 là các thuộc tính công khai và được hiển thị như một phần của API của lớp. Điều này có nghĩa là người dùng của bạn có thể và sẽ thay đổi giá trị của họ bất cứ khi nào họ muốn

>>>

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
9

Việc hiển thị các thuộc tính như

# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
14 và
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
63 là thông lệ phổ biến trong Python. Vì vậy, người dùng của bạn sẽ trực tiếp truy cập và thay đổi loại thuộc tính này trong mã của họ

Công khai các thuộc tính của bạn, như trong ví dụ trên, là một cách phổ biến trong Python. Trong những trường hợp này, việc chuyển sang getters và setters sẽ đưa ra những thay đổi đột phá. Vì vậy, làm thế nào để bạn đối phó với các tình huống yêu cầu thêm hành vi vào thuộc tính của bạn?

Loại bỏ các quảng cáo

Sử dụng thuộc tính thay vì Getters và Setters. Con đường Python

Cách Pythonic để gắn hành vi vào một thuộc tính là biến chính thuộc tính đó thành một thuộc tính. Các thuộc tính kết hợp các phương thức để nhận, đặt, xóa và ghi lại dữ liệu cơ bản. Do đó, thuộc tính là thuộc tính đặc biệt với hành vi bổ sung

Bạn có thể sử dụng các thuộc tính giống như cách bạn sử dụng các thuộc tính thông thường. Khi bạn truy cập một thuộc tính, phương thức getter đính kèm của nó sẽ tự động được gọi. Tương tự như vậy, khi bạn thay đổi thuộc tính, phương thức setter của nó sẽ được gọi. Hành vi này cung cấp phương tiện để đính kèm chức năng vào các thuộc tính của bạn mà không đưa ra các thay đổi vi phạm trong API của mã của bạn

Ví dụ về cách các thuộc tính có thể giúp bạn đính kèm hành vi với các thuộc tính, giả sử rằng bạn cần một lớp

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
66 như một phần của hệ thống quản lý nhân viên. Bạn bắt đầu với việc triển khai cơ bản sau

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
3

Hàm tạo của lớp này nhận hai đối số, tên và ngày sinh của nhân viên trong tay. Các thuộc tính này được lưu trữ trực tiếp trong hai thuộc tính thể hiện,

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
67 và
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
68

Bạn có thể bắt đầu sử dụng lớp học ngay lập tức

>>>

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
6

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
66 cho phép bạn tạo các phiên bản cho phép bạn truy cập trực tiếp vào tên và ngày sinh được liên kết. Lưu ý rằng bạn cũng có thể thay đổi các thuộc tính bằng cách sử dụng phép gán trực tiếp

Khi dự án của bạn phát triển, bạn có những yêu cầu mới. Bạn cần lưu tên nhân viên bằng chữ in hoa và biến ngày sinh thành đối tượng

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
90. Để đáp ứng các yêu cầu này mà không vi phạm API của bạn bằng các phương thức getter và setter cho
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
67 và
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
68, bạn có thể sử dụng các thuộc tính

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
1

Trong phiên bản nâng cao này của

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
66, bạn biến
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
67 và
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
68 thành các thuộc tính bằng cách sử dụng trình trang trí
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
96. Bây giờ mỗi thuộc tính có một phương thức getter và setter được đặt tên theo chính thuộc tính đó. Lưu ý rằng setter của
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
67 biến tên đầu vào thành chữ hoa. Tương tự, setter của
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
68 tự động chuyển đổi ngày đầu vào thành đối tượng
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
90 cho bạn

Như đã đề cập trước đây, một tính năng thú vị của các thuộc tính là bạn có thể sử dụng chúng như các thuộc tính thông thường

>>>

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
9

Mát mẻ. Bạn đã thêm hành vi vào các thuộc tính

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
67 và
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
68 mà không ảnh hưởng đến API của lớp bạn. Với các thuộc tính, bạn đã có được khả năng tham chiếu đến các thuộc tính này giống như đối với các thuộc tính thông thường. Đằng sau hậu trường, Python đảm nhiệm việc chạy các phương thức thích hợp cho bạn

Bạn phải tránh vi phạm mã của người dùng bằng cách đưa ra các thay đổi trong API của mình. Trình trang trí

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
96 của Python là cách Pythonic để làm điều đó. Các thuộc tính được đề xuất chính thức trong PEP 8 như là cách phù hợp để xử lý các thuộc tính cần hành vi chức năng

Đối với các thuộc tính dữ liệu công khai đơn giản, tốt nhất là chỉ hiển thị tên thuộc tính mà không có các phương thức truy cập/biến đổi phức tạp. Hãy nhớ rằng Python cung cấp một con đường dễ dàng để nâng cao trong tương lai, nếu bạn thấy rằng một thuộc tính dữ liệu đơn giản cần phát triển hành vi chức năng. Trong trường hợp đó, hãy sử dụng các thuộc tính để ẩn việc triển khai chức năng đằng sau cú pháp truy cập thuộc tính dữ liệu đơn giản. (Nguồn)

Các thuộc tính của Python có rất nhiều trường hợp sử dụng tiềm năng. Ví dụ: bạn có thể sử dụng các thuộc tính để tạo các thuộc tính chỉ đọc, chỉ đọc và ghi một cách đơn giản và dễ hiểu. Thuộc tính cho phép bạn xóa và ghi lại các thuộc tính cơ bản và hơn thế nữa. Quan trọng hơn, các thuộc tính cho phép bạn làm cho các thuộc tính thông thường hoạt động giống như các thuộc tính được quản lý với hành vi được đính kèm mà không thay đổi cách bạn làm việc với chúng

Do các thuộc tính, các nhà phát triển Python có xu hướng thiết kế các lớp API của họ bằng cách sử dụng một số nguyên tắc

  • Sử dụng các thuộc tính chung bất cứ khi nào thích hợp, ngay cả khi bạn muốn thuộc tính đó yêu cầu hành vi chức năng trong tương lai
  • Tránh xác định các phương thức setter và getter cho các thuộc tính của bạn. Bạn luôn có thể biến chúng thành tài sản nếu cần
  • Sử dụng thuộc tính khi bạn cần đính kèm hành vi với thuộc tính và tiếp tục sử dụng chúng làm thuộc tính thông thường trong mã của mình
  • Tránh các tác dụng phụ trong các thuộc tính vì không ai mong muốn các hoạt động như gán sẽ gây ra bất kỳ tác dụng phụ nào

Các thuộc tính của Python rất tuyệt. Do đó, mọi người có xu hướng lạm dụng chúng. Nói chung, bạn chỉ nên sử dụng các thuộc tính khi cần thêm xử lý bổ sung cho một thuộc tính cụ thể. Biến tất cả các thuộc tính của bạn thành thuộc tính sẽ lãng phí thời gian của bạn. Nó cũng có thể ngụ ý các vấn đề về hiệu suất và khả năng bảo trì

Loại bỏ các quảng cáo

Thay thế Getters và Setters bằng các công cụ nâng cao hơn

Cho đến thời điểm này, bạn đã học cách tạo các phương thức getter và setter cơ bản để quản lý các thuộc tính của các lớp của bạn. Bạn cũng đã học được rằng các thuộc tính là cách Pythonic tiếp cận vấn đề thêm hành vi chức năng vào các thuộc tính hiện có

Trong các phần sau, bạn sẽ tìm hiểu về các công cụ và kỹ thuật khác mà bạn có thể sử dụng để thay thế các phương thức getter và setter trong Python

Mô tả của Python

Bộ mô tả là một tính năng Python nâng cao cho phép bạn tạo các thuộc tính với các hành vi được đính kèm trong các lớp của bạn. Để tạo bộ mô tả, bạn cần sử dụng giao thức bộ mô tả, đặc biệt là các phương thức đặc biệt

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
33 và
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
34

Mô tả khá giống với thuộc tính. Trên thực tế, thuộc tính là một kiểu mô tả đặc biệt. Tuy nhiên, các mô tả thông thường mạnh hơn các thuộc tính và có thể được sử dụng lại thông qua các lớp khác nhau

Để minh họa cách sử dụng bộ mô tả để tạo các thuộc tính có hành vi chức năng, hãy nói rằng bạn cần tiếp tục phát triển lớp

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
66 của mình. Lần này, bạn cần một thuộc tính để lưu trữ ngày mà một nhân viên bắt đầu làm việc cho công ty

# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
30

Trong bản cập nhật này, bạn đã thêm một thuộc tính khác vào

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
66. Thuộc tính mới này sẽ cho phép bạn quản lý ngày bắt đầu làm việc của từng nhân viên. Một lần nữa, phương thức setter chuyển đổi ngày từ một chuỗi thành một đối tượng
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
90

Lớp học này hoạt động như mong đợi. Tuy nhiên, nó bắt đầu lặp đi lặp lại và nhàm chán. Vì vậy, bạn quyết định cấu trúc lại lớp. Bạn nhận thấy rằng bạn đang thực hiện cùng một thao tác trong cả hai thuộc tính liên quan đến ngày tháng và bạn nghĩ đến việc sử dụng một bộ mô tả để đóng gói chức năng lặp đi lặp lại

# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
31

Mã này sạch hơn và ít lặp lại hơn phiên bản trước. Trong bản cập nhật này, bạn tạo một bộ mô tả

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
38 để quản lý các thuộc tính liên quan đến ngày tháng. Bộ mô tả có phương thức
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
39 tự động lưu tên thuộc tính. Nó cũng có các phương thức
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
33 và
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
34 hoạt động tương ứng với vai trò là getter và setter của thuộc tính

Hai triển khai của

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
66 trong phần này hoạt động tương tự nhau. Đi trước và cung cấp cho họ một thử

Nói chung, nếu bạn thấy mình làm lộn xộn các lớp của mình với các định nghĩa thuộc tính tương tự, thì bạn nên cân nhắc sử dụng một bộ mô tả để thay thế

Phương thức # label.py class Label: def __init__(self, text, font): self.set_text(text) self.font = font def get_text(self): return self._text def set_text(self, value): self._text = value.upper() # Attached behavior 63 và # label.py class Label: def __init__(self, text, font): self.set_text(text) self.font = font def get_text(self): return self._text def set_text(self, value): self._text = value.upper() # Attached behavior 64

Một cách khác để thay thế các phương thức getter và setter truyền thống trong Python là sử dụng các phương thức đặc biệt

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
63 và
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
64 để quản lý các thuộc tính của bạn. Xem xét ví dụ sau, định nghĩa một lớp
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
67. Lớp tự động chuyển đổi tọa độ đầu vào thành số dấu phẩy động

# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
32

Trình khởi tạo của

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
67 có hai tọa độ,
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
69 và
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
10. Phương thức
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
64 trả về tọa độ được đại diện bởi
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
12. Để làm điều này, phương thức sử dụng từ điển không gian tên cá thể,
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
13. Lưu ý rằng tên cuối cùng của thuộc tính sẽ có dấu gạch dưới trước bất cứ điều gì bạn chuyển vào
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
12. Python tự động gọi
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
64 bất cứ khi nào bạn truy cập một thuộc tính của
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
67 bằng cách sử dụng ký hiệu dấu chấm

Phương thức

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
63 thêm hoặc cập nhật các thuộc tính. Trong ví dụ này,
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
63 hoạt động trên từng tọa độ và chuyển đổi nó thành số dấu phẩy động bằng cách sử dụng hàm
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
19 tích hợp. Một lần nữa, Python gọi
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
63 bất cứ khi nào bạn chạy một thao tác gán trên bất kỳ thuộc tính nào của lớp chứa

Đây là cách lớp này hoạt động trong thực tế

>>>

# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
33

Lớp

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
67 của bạn tự động chuyển đổi các giá trị tọa độ thành các số dấu phẩy động. Bạn có thể truy cập các tọa độ,
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
69 và
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
10, giống như bất kỳ thuộc tính thông thường nào khác. Tuy nhiên, các hoạt động truy cập và đột biến lần lượt đi qua
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
64 và
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
63

Lưu ý rằng

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
67 cho phép bạn truy cập tọa độ dưới dạng thuộc tính công khai. Tuy nhiên, nó lưu trữ chúng dưới dạng các thuộc tính không công khai. Bạn có thể xác nhận hành vi này bằng chức năng
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
97 tích hợp

Ví dụ trong phần này hơi kỳ lạ và có thể bạn sẽ không sử dụng thứ gì đó tương tự trong mã của mình. Tuy nhiên, các công cụ mà bạn đã sử dụng trong ví dụ này cho phép bạn thực hiện xác thực hoặc chuyển đổi khi truy cập và thay đổi thuộc tính, giống như các phương thức getter và setter thực hiện

Theo một nghĩa nào đó,

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
64 và
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
63 là một kiểu triển khai chung của mẫu getter và setter. Về cơ bản, các phương thức này hoạt động như getters và setters hỗ trợ truy cập và thay đổi thuộc tính thông thường trong Python

Loại bỏ các quảng cáo

Quyết định nên sử dụng Getters và Setters hay Properties trong Python

Trong mã hóa trong thế giới thực, bạn sẽ tìm thấy một vài trường hợp sử dụng trong đó các phương thức getter và setter có thể được ưu tiên hơn các thuộc tính, mặc dù các thuộc tính nói chung là cách sử dụng của Pythonic

Ví dụ: các phương thức getter và setter có thể phù hợp hơn để xử lý các tình huống mà bạn cần

  • Chạy các phép biến đổi tốn kém khi truy cập thuộc tính hoặc đột biến
  • Lấy thêm đối số và cờ
  • sử dụng thừa kế
  • Tăng các ngoại lệ liên quan đến truy cập thuộc tính và đột biến
  • Tạo điều kiện tích hợp trong các nhóm phát triển không đồng nhất

Trong các phần sau, bạn sẽ đi sâu vào các trường hợp sử dụng này và tại sao các phương thức getter và setter có thể tốt hơn các thuộc tính để tiếp cận các trường hợp đó

Tránh các phương thức chậm đằng sau các thuộc tính

Bạn nên tránh ẩn các hoạt động chậm đằng sau thuộc tính Python. Người dùng API của bạn sẽ mong đợi quyền truy cập và biến đổi thuộc tính hoạt động như quyền truy cập và biến đổi thông thường. Nói cách khác, người dùng sẽ mong đợi các hoạt động này diễn ra ngay lập tức và không có tác dụng phụ

Đi quá xa so với kỳ vọng đó sẽ khiến API của bạn trở nên kỳ quặc và khó sử dụng, vi phạm nguyên tắc ít bất ngờ nhất

Ngoài ra, nếu người dùng của bạn liên tục truy cập và thay đổi các thuộc tính của bạn trong một vòng lặp, thì mã của họ có thể liên quan đến quá nhiều chi phí, điều này có thể tạo ra các vấn đề lớn và không mong muốn về hiệu suất

Ngược lại, các phương thức getter và setter truyền thống làm rõ rằng việc truy cập hoặc thay đổi một thuộc tính nhất định xảy ra thông qua một lệnh gọi phương thức. Thật vậy, người dùng của bạn sẽ biết rằng việc gọi một phương thức có thể mất thời gian và hiệu suất mã của họ có thể thay đổi đáng kể vì điều đó

Việc làm rõ ràng các dữ kiện đó trong API của bạn có thể giúp giảm thiểu sự ngạc nhiên của người dùng khi họ truy cập và thay đổi các thuộc tính của bạn trong mã của họ

Nói tóm lại, nếu bạn định sử dụng thuộc tính để quản lý thuộc tính, thì hãy đảm bảo rằng các phương thức đằng sau thuộc tính đó nhanh và không gây tác dụng phụ. Ngược lại, nếu bạn đang xử lý các phương thức của bộ truy cập và bộ biến đổi chậm, thì hãy ưu tiên các phương thức getter và setters truyền thống hơn các thuộc tính

Lấy thêm đối số và cờ

Không giống như các thuộc tính Python, các phương thức getter và setter truyền thống cho phép truy cập và thay đổi thuộc tính linh hoạt hơn. Ví dụ: giả sử bạn có lớp

# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
300 với thuộc tính
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
68. Thuộc tính này phải không đổi trong suốt cuộc đời của một người. Do đó, bạn quyết định rằng thuộc tính sẽ ở chế độ chỉ đọc

Tuy nhiên, do lỗi của con người tồn tại, bạn sẽ gặp phải trường hợp ai đó mắc lỗi khi nhập ngày sinh của một người nhất định. Bạn có thể giải quyết vấn đề này bằng cách cung cấp phương thức setter nhận cờ

# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
302, như trong ví dụ bên dưới

# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
34

Bạn cung cấp các phương thức getter và setter truyền thống cho thuộc tính

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
68 trong ví dụ này. Phương thức setter nhận thêm một đối số gọi là
# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
302, cho phép bạn buộc sửa đổi ngày sinh của một người

Ghi chú. Các phương thức setter truyền thống thường không nhận nhiều hơn một đối số. Ví dụ trên có thể trông kỳ lạ hoặc thậm chí không chính xác đối với một số nhà phát triển. Tuy nhiên, ý định của nó là giới thiệu một kỹ thuật có thể hữu ích trong một số tình huống.

Đây là cách lớp này hoạt động

>>>

# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
35

Khi bạn cố gắng sửa đổi ngày sinh của Jane bằng cách sử dụng

# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
305 mà không đặt
# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
302 thành
# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
307, bạn sẽ nhận được thông báo
# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
308 rằng không thể đặt thuộc tính. Ngược lại, nếu bạn đặt
# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
302 thành
# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
307, thì bạn sẽ có thể cập nhật ngày sinh của Jane để sửa bất kỳ lỗi nào xảy ra khi nhập ngày

Điều quan trọng cần lưu ý là các thuộc tính Python không chấp nhận các đối số bổ sung trong các phương thức setter của chúng. Họ chỉ chấp nhận giá trị được đặt hoặc cập nhật

Loại bỏ các quảng cáo

Sử dụng thừa kế. Getter và Setters so với Thuộc tính

Một vấn đề với các thuộc tính Python là chúng không hoạt động tốt trong các tình huống kế thừa. Ví dụ: giả sử bạn cần mở rộng hoặc sửa đổi phương thức getter của thuộc tính trong lớp con. Trong thực tế, không có cách nào an toàn để làm điều này. Bạn không thể chỉ ghi đè phương thức getter và mong đợi phần còn lại của chức năng thuộc tính vẫn giữ nguyên như trong lớp cha

Sự cố này xảy ra do các phương thức getter và setter bị ẩn bên trong thuộc tính. Chúng không được kế thừa một cách độc lập mà là một tổng thể. Do đó, khi bạn ghi đè phương thức getter của một thuộc tính được kế thừa từ lớp cha, bạn sẽ ghi đè toàn bộ thuộc tính, bao gồm phương thức setter và phần còn lại của các thành phần bên trong của nó

Ví dụ, hãy xem xét hệ thống phân cấp lớp sau

# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
36

Trong ví dụ này, bạn ghi đè phương thức getter của thuộc tính

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
67 trong
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
66. Bằng cách này, bạn đang ngầm ghi đè lên toàn bộ thuộc tính
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
67, bao gồm cả chức năng setter của nó

>>>

# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
37

Bây giờ

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
67 là thuộc tính chỉ đọc vì phương thức setter của lớp cha không được kế thừa mà bị ghi đè bởi một thuộc tính hoàn toàn mới. Bạn không muốn điều đó, phải không?

Nếu bạn sử dụng các phương thức getter và setter truyền thống thì sự cố sẽ không xảy ra

# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
38

Phiên bản này của

# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
300 cung cấp các phương thức getter và setter độc lập. Các lớp con của
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
66
# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
300, ghi đè phương thức getter cho thuộc tính tên. Thực tế này không ảnh hưởng đến phương thức setter mà
# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
66 kế thừa thành công từ lớp cha của nó,
# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
300

Đây là cách phiên bản mới này của

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
66 hoạt động

>>>

# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
39

Bây giờ

# label.py

class Label:
    def __init__(self, text, font):
        self.set_text(text)
        self.font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value.upper()  # Attached behavior
66 hoàn toàn hoạt động. Phương thức getter ghi đè hoạt động như mong đợi. Phương thức setter cũng hoạt động vì nó được kế thừa thành công từ
# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
300

Tăng ngoại lệ khi truy cập thuộc tính hoặc đột biến

Hầu hết thời gian, bạn sẽ không mong đợi một câu lệnh gán như

# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
323 đưa ra một ngoại lệ. Ngược lại, bạn có thể mong đợi các phương thức đưa ra các ngoại lệ để phản hồi các lỗi. Về vấn đề này, các phương thức getter và setter truyền thống rõ ràng hơn các thuộc tính

Ví dụ:

# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
324 trông không giống thứ gì đó có thể đưa ra ngoại lệ. Nó trông giống như một phép gán thuộc tính thông thường. Mặt khác,
# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
325 trông giống như thứ gì đó có thể gây ra ngoại lệ, có thể là
# label.py

class Label:
    def __init__(self, text, font):
        self._text = text
        self._font = font

    def get_text(self):
        return self._text

    def set_text(self, value):
        self._text = value

    def get_font(self):
        return self._font

    def set_font(self, value):
        self._font = value
326, vì giá trị đầu vào không phải là một URL hợp lệ cho một trang web. Trong ví dụ này, phương thức setter rõ ràng hơn. Nó thể hiện rõ ràng hành vi có thể có của mã

Theo nguyên tắc thông thường, tránh đưa ra các ngoại lệ từ các thuộc tính Python của bạn trừ khi bạn đang sử dụng một thuộc tính để cung cấp các thuộc tính chỉ đọc. Nếu bạn cần đưa ra các ngoại lệ đối với quyền truy cập hoặc biến đổi thuộc tính, thì bạn nên cân nhắc sử dụng các phương thức getter và setter thay vì các thuộc tính

Trong những trường hợp này, việc sử dụng getters và setters sẽ làm giảm sự ngạc nhiên của người dùng và làm cho mã của bạn phù hợp hơn với các thông lệ và kỳ vọng chung

Tạo điều kiện tích hợp nhóm và di chuyển dự án

Cung cấp các phương thức getter và setter là thông lệ phổ biến trong nhiều ngôn ngữ lập trình được thiết lập tốt. Nếu bạn đang làm việc trên một dự án Python với một nhóm các nhà phát triển đến từ các nền tảng ngôn ngữ khác, thì rất có thể mẫu getter và setter sẽ trông quen thuộc hơn với họ so với các thuộc tính Python

Trong loại nhóm không đồng nhất này, việc sử dụng getters và setters có thể tạo điều kiện thuận lợi cho việc tích hợp các nhà phát triển mới vào nhóm

Sử dụng mẫu getter và setter cũng có thể thúc đẩy tính nhất quán của API. Nó cho phép bạn cung cấp một API dựa trên các lệnh gọi phương thức chứ không phải là một API kết hợp các lệnh gọi phương thức với truy cập và thay đổi thuộc tính trực tiếp

Thông thường, khi một dự án Python phát triển, bạn có thể cần chuyển dự án từ Python sang ngôn ngữ khác. Ngôn ngữ mới có thể không có các thuộc tính hoặc chúng có thể không hoạt động như các thuộc tính của Python. Trong những tình huống này, việc sử dụng getters và setters truyền thống ngay từ đầu sẽ giúp việc di chuyển trong tương lai bớt khó khăn hơn

Trong tất cả các tình huống trên, bạn nên cân nhắc sử dụng các phương thức getter và setter truyền thống thay vì các thuộc tính trong Python

Loại bỏ các quảng cáo

Sự kết luận

Bây giờ bạn đã biết phương thức getter và setter là gì và chúng đến từ đâu. Các phương pháp này cho phép truy cập và thay đổi thuộc tính trong khi tránh thay đổi API. Tuy nhiên, chúng không quá phổ biến trong Python vì sự tồn tại của các thuộc tính. Thuộc tính cho phép bạn thêm hành vi vào thuộc tính của mình đồng thời tránh phá vỡ các thay đổi trong API của bạn

Mặc dù các thuộc tính là cách Pythonic để thay thế các getter và setters truyền thống, nhưng các thuộc tính có thể có một số nhược điểm thực tế mà bạn có thể khắc phục bằng getters và setters

Trong hướng dẫn này, bạn đã học cách

  • Viết các phương thức getter và setter trong Python
  • Sử dụng các thuộc tính Python để thay thế các phương thức getter và setter
  • Sử dụng các công cụ Python, như bộ mô tả, để thay thế getters và setters
  • Quyết định khi nào các phương thức setter và getter có thể là công cụ phù hợp cho công việc

Với tất cả kiến ​​thức này, giờ đây bạn có thể quyết định khi nào nên sử dụng các phương thức hoặc thuộc tính getter và setter trong các lớp Python của mình

Mã nguồn. Nhấp vào đây để lấy mã nguồn miễn phí chỉ cho bạn cách thức và thời điểm sử dụng getters, setters và thuộc tính trong Python

Đánh dấu là đã hoàn thành

🐍 Thủ thuật Python 💌

Nhận một Thủ thuật Python ngắn và hấp dẫn được gửi đến hộp thư đến của bạn vài ngày một lần. Không có thư rác bao giờ. Hủy đăng ký bất cứ lúc nào. Được quản lý bởi nhóm Real Python

Con trăn setter là gì?

Gửi cho tôi thủ thuật Python »

Giới thiệu về Leodanis Pozo Ramos

Con trăn setter là gì?
Con trăn setter là gì?

Leodanis là một kỹ sư công nghiệp yêu thích Python và phát triển phần mềm. Anh ấy là một nhà phát triển Python tự học với hơn 6 năm kinh nghiệm. Anh ấy là một nhà văn đam mê kỹ thuật với số lượng bài báo được xuất bản ngày càng tăng trên Real Python và các trang web khác

» Tìm hiểu thêm về Leodanis


Mỗi hướng dẫn tại Real Python được tạo bởi một nhóm các nhà phát triển để nó đáp ứng các tiêu chuẩn chất lượng cao của chúng tôi. Các thành viên trong nhóm đã làm việc trong hướng dẫn này là

Con trăn setter là gì?

Aldren

Con trăn setter là gì?

Geir Arne

Con trăn setter là gì?

kate

Con trăn setter là gì?

Philipp

Bậc thầy Kỹ năng Python trong thế giới thực Với quyền truy cập không giới hạn vào Python thực

Con trăn setter là gì?

Tham gia với chúng tôi và có quyền truy cập vào hàng nghìn hướng dẫn, khóa học video thực hành và cộng đồng các Pythonistas chuyên gia

Nâng cao kỹ năng Python của bạn »

Bậc thầy Kỹ năng Python trong thế giới thực
Với quyền truy cập không giới hạn vào Python thực

Tham gia với chúng tôi và có quyền truy cập vào hàng ngàn hướng dẫn, khóa học video thực hành và cộng đồng Pythonistas chuyên gia

Nâng cao kỹ năng Python của bạn »

Bạn nghĩ sao?

Đánh giá bài viết này

Tweet Chia sẻ Chia sẻ Email

Bài học số 1 hoặc điều yêu thích mà bạn đã học được là gì?

Mẹo bình luận. Những nhận xét hữu ích nhất là những nhận xét được viết với mục đích học hỏi hoặc giúp đỡ các sinh viên khác. Nhận các mẹo để đặt câu hỏi hay và nhận câu trả lời cho các câu hỏi phổ biến trong cổng thông tin hỗ trợ của chúng tôi

Setter được sử dụng để làm gì?

Getters và setters được sử dụng để bảo vệ dữ liệu của bạn, đặc biệt khi tạo lớp. Đối với mỗi biến thể hiện, phương thức getter trả về giá trị của nó trong khi phương thức setter đặt hoặc cập nhật giá trị của nó .

Việc sử dụng getter và setter trong Python là gì?

Như tên gợi ý, getters là các phương thức giúp truy cập các thuộc tính riêng tư hoặc lấy giá trị của các thuộc tính riêng tư và setters là các phương thức giúp thay đổi hoặc đặt giá trị của . .

Công cụ trang trí setter trong Python là gì?

@property là công cụ trang trí tích hợp sẵn cho hàm property() trong Python . Nó được sử dụng để cung cấp chức năng "đặc biệt" cho một số phương thức nhất định để làm cho chúng hoạt động như getters, setters hoặc deleters khi chúng ta định nghĩa các thuộc tính trong một lớp.

Sự khác biệt giữa setter và constructor là gì?

Các hàm tạo được sử dụng để khởi tạo biến thể hiện của một lớp hoặc, tạo các đối tượng. Các phương thức setter/getter được sử dụng để gán/thay đổi và truy xuất các giá trị của các biến thể hiện của một lớp