Trình trang trí Python setter

Getters [còn được gọi là 'người truy cập'] và setters [hay còn gọi là. 'mutators'] được sử dụng trong nhiều ngôn ngữ lập trình hướng đối tượng để đảm bảo nguyên tắc đóng gói dữ liệu. Đóng gói dữ liệu - như chúng ta đã học trong phần giới thiệu về Lập trình hướng đối tượng của hướng dẫn của chúng tôi - được coi là gói dữ liệu với các phương thức hoạt động trên chúng. Các phương thức này tất nhiên là getter để lấy dữ liệu và setter để thay đổi dữ liệu. Theo nguyên tắc này, các thuộc tính của một lớp được đặt ở chế độ riêng tư để ẩn và bảo vệ chúng.

Thật không may, nhiều người tin rằng một lớp Python phù hợp nên đóng gói các thuộc tính riêng tư bằng cách sử dụng getters và setters. Ngay khi một trong những lập trình viên này giới thiệu một thuộc tính mới, anh ấy hoặc cô ấy sẽ biến nó thành một biến riêng tư và tạo "tự động" một getter và setter cho thuộc tính này. Những lập trình viên như vậy thậm chí có thể sử dụng trình chỉnh sửa hoặc IDE, tự động tạo getters và setters cho tất cả các thuộc tính riêng tư. Những công cụ này thậm chí còn cảnh báo lập trình viên nếu họ sử dụng thuộc tính công khai. Các lập trình viên Java sẽ nhăn mày, sếch mũi, thậm chí là hét lên kinh hãi khi đọc những điều sau đây. Cách Pythonic để giới thiệu các thuộc tính là đặt chúng ở chế độ công khai

Chúng tôi sẽ giải thích điều này sau. Đầu tiên, chúng tôi chứng minh trong ví dụ sau, cách chúng tôi có thể thiết kế một lớp theo cách Javaesque với getters và setters để đóng gói thuộc tính private

p1.set_x[47]
p1.set_x[p1.get_x[]+p2.get_x[]]
p1.get_x[]
4

class P:
    def __init__[self, x]:
        self.__x = x
    def get_x[self]:
        return self.__x
    def set_x[self, x]:
        self.__x = x

Chúng ta có thể thấy trong phiên demo sau đây cách làm việc với lớp này và các phương thức

from mutators import P
p1 = P[42]
p2 = P[4711]
p1.get_x[]

ĐẦU RA

42

p1.set_x[47]
p1.set_x[p1.get_x[]+p2.get_x[]]
p1.get_x[]

ĐẦU RA

4758

Bạn nghĩ sao về câu nói "p1. set_x[p1. get_x[]+p2. get_x[]]"? Thật tệ phải không? Viết một biểu thức như sau sẽ dễ dàng hơn rất nhiều nếu chúng ta có một thuộc tính công khai x

p1.x = p1.x + p2.x

Một nhiệm vụ như vậy dễ viết hơn và trên hết là dễ đọc hơn biểu thức Javaesque

Hãy viết lại lớp P theo cách Pythonic. Không getter, không setter và thay vì thuộc tính riêng tư

p1.set_x[47]
p1.set_x[p1.get_x[]+p2.get_x[]]
p1.get_x[]
4, chúng tôi sử dụng thuộc tính công khai

________số 8

Đẹp, phải không?

from p import P
p1 = P[42]
p2 = P[4711]
p1.x

ĐẦU RA

42

class P:
    def __init__[self, x]:
        self.__x = x
    def get_x[self]:
        return self.__x
    def set_x[self, x]:
        self.__x = x
1

ĐẦU RA

4758

"Nhưng, nhưng, nhưng, nhưng, nhưng. ", chúng ta có thể nghe thấy chúng hú hét, "Nhưng KHÔNG CÓ DỮ LIỆU GÓP GÓP. " Có, trong trường hợp này không có đóng gói dữ liệu. Chúng tôi không cần nó trong trường hợp này. Điều duy nhất get_x và set_x trong ví dụ ban đầu của chúng tôi đã làm là "lấy dữ liệu qua" mà không cần làm gì thêm

Nhưng điều gì sẽ xảy ra nếu chúng ta muốn thay đổi cách triển khai trong tương lai? . Giả sử chúng ta muốn thay đổi cách triển khai như thế này. Thuộc tính x có thể có giá trị từ 0 đến 1000. Nếu giá trị lớn hơn 1000 được chỉ định, x phải được đặt thành 1000. Tương ứng, x phải được đặt thành 0, nếu giá trị nhỏ hơn 0

Thật dễ dàng để thay đổi lớp P đầu tiên của chúng tôi để giải quyết vấn đề này. Chúng tôi thay đổi phương thức set_x cho phù hợp

from mutators import P
p1 = P[42]
p2 = P[4711]
p1.get_x[]
1

Phiên Python sau đây cho thấy nó hoạt động theo cách chúng tôi muốn nó hoạt động

from mutators import P
p1 = P[42]
p2 = P[4711]
p1.get_x[]
2

ĐẦU RA

from mutators import P
p1 = P[42]
p2 = P[4711]
p1.get_x[]
3

from mutators import P
p1 = P[42]
p2 = P[4711]
p1.get_x[]
4

ĐẦU RA

from mutators import P
p1 = P[42]
p2 = P[4711]
p1.get_x[]
5

from mutators import P
p1 = P[42]
p2 = P[4711]
p1.get_x[]
6

ĐẦU RA

from mutators import P
p1 = P[42]
p2 = P[4711]
p1.get_x[]
7

Nhưng có một nhược điểm. Giả sử chúng ta đã thiết kế lớp của mình với thuộc tính public và không có phương thức

from mutators import P
p1 = P[42]
p2 = P[4711]
p1.get_x[]
8

Mọi người đã sử dụng nó rất nhiều và họ đã viết mã như thế này

from mutators import P
p1 = P[42]
p2 = P[4711]
p1.get_x[]
9

ĐẦU RA

42
0

Nếu chúng ta thay đổi P2 bây giờ theo cách của lớp P, lớp mới của chúng ta sẽ phá vỡ giao diện, vì thuộc tính x sẽ không còn khả dụng nữa. Đó là lý do tại sao trong Java e. g. mọi người được khuyến nghị chỉ sử dụng các thuộc tính riêng tư với getters và setters để họ có thể thay đổi cách triển khai mà không phải thay đổi giao diện

Nhưng Python đưa ra một giải pháp cho vấn đề này. Giải pháp được gọi là thuộc tính

Lớp có thuộc tính trông như thế này

42
1

Phương thức được sử dụng để nhận giá trị được trang trí bằng "@property", tôi. e. chúng tôi đặt dòng này trực tiếp trước tiêu đề. Phương thức phải hoạt động như setter được trang trí bằng "@x. người định cư". Nếu chức năng được gọi là "f", chúng ta sẽ phải trang trí nó bằng "@f. người định cư". Hai điều đáng chú ý. Chúng tôi chỉ đặt dòng mã "self. x = x" trong phương thức

p1.set_x[47]
p1.set_x[p1.get_x[]+p2.get_x[]]
p1.get_x[]
6 và phương thức thuộc tính x được sử dụng để kiểm tra giới hạn của các giá trị. Điều thú vị thứ hai là chúng tôi đã viết "hai" phương thức có cùng tên và khác số tham số "def x[self]" và "def x[self,x]". Chúng tôi đã học được trong một chương trước của khóa học rằng điều này là không thể. Nó hoạt động ở đây do trang trí

42
2

ĐẦU RA

from mutators import P
p1 = P[42]
p2 = P[4711]
p1.get_x[]
3

42
4

ĐẦU RA

from mutators import P
p1 = P[42]
p2 = P[4711]
p1.get_x[]
7

Ngoài ra, chúng tôi có thể đã sử dụng một cú pháp khác mà không cần trang trí để xác định thuộc tính. Như bạn có thể thấy, mã chắc chắn là kém thanh lịch hơn và chúng tôi phải đảm bảo rằng chúng tôi sử dụng lại hàm getter trong phương thức

p1.set_x[47]
p1.set_x[p1.get_x[]+p2.get_x[]]
p1.get_x[]
6

42
6

Vẫn còn một vấn đề khác trong phiên bản mới nhất. Bây giờ chúng ta có hai cách để truy cập hoặc thay đổi giá trị của x. Bằng cách sử dụng "p1. x = 42" hoặc bằng "p1. set_x[42]". Bằng cách này, chúng tôi đang vi phạm một trong những nguyên tắc cơ bản của Python. "Nên có một-- và tốt nhất là chỉ có một --cách rõ ràng để làm điều đó. " [xem Thiền của Python]

Chúng ta có thể dễ dàng khắc phục sự cố này bằng cách chuyển các phương thức getter và setter thành các phương thức riêng tư, những người dùng trong lớp P của chúng ta không thể truy cập được nữa

42
7

Mặc dù chúng tôi đã khắc phục sự cố này bằng cách sử dụng trình thu thập và thiết lập riêng tư, nhưng phiên bản có trình trang trí "@property" là cách Pythonic để thực hiện

Từ những gì chúng tôi đã viết cho đến nay, cũng như những gì có thể thấy trong các cuốn sách và hướng dẫn khác, chúng tôi có thể dễ dàng có ấn tượng rằng có một kết nối một-một giữa các thuộc tính [hoặc phương thức trình biến đổi] và các thuộc tính, tôi. e. rằng mỗi thuộc tính có hoặc nên có thuộc tính riêng [hoặc cặp getter-setter] và ngược lại. Ngay cả trong các ngôn ngữ hướng đối tượng khác ngoài Python, việc triển khai một lớp như thế thường không phải là một ý tưởng hay. Lý do chính là nhiều thuộc tính chỉ cần thiết bên trong và việc tạo giao diện cho người dùng của lớp làm tăng khả năng sử dụng của lớp một cách không cần thiết. Người dùng có thể của một lớp không nên bị "chết đuối" với vô số - chủ yếu là không cần thiết - các phương thức hoặc thuộc tính

Ví dụ sau đây cho thấy một lớp có các thuộc tính bên trong, không thể truy cập từ bên ngoài. Đây là các thuộc tính riêng

p1.set_x[47]
p1.set_x[p1.get_x[]+p2.get_x[]]
p1.get_x[]
8
p1.set_x[47]
p1.set_x[p1.get_x[]+p2.get_x[]]
p1.get_x[]
9 và
4758
0. Hơn nữa, chúng tôi chỉ ra rằng một thuộc tính có thể được suy ra từ các giá trị của nhiều thuộc tính. Thuộc tính "điều kiện" của ví dụ của chúng tôi trả về điều kiện của robot trong một chuỗi mô tả. Điều kiện phụ thuộc vào tổng giá trị của tâm linh và điều kiện vật chất của robot

42
8

ĐẦU RA

42
9

Đào tạo Python trực tiếp

Thưởng thức trang này?

Nhìn thấy. Tổng quan về các khóa học Python trực tiếp

đăng ký tại đây

Thuộc tính công khai thay vì riêng tư

Hãy tóm tắt cách sử dụng các thuộc tính private và public, getters và setters và các thuộc tính. Giả sử rằng chúng ta đang thiết kế một lớp mới và chúng ta đang cân nhắc về một thể hiện hoặc thuộc tính lớp "OurAtt", mà chúng ta cần để thiết kế lớp của mình. Chúng ta phải quan sát các vấn đề sau

  • Giá trị của "OurAtt" có cần thiết cho những người dùng có thể thuộc lớp của chúng ta không?
  • Nếu không, chúng ta có thể hoặc nên biến nó thành một thuộc tính riêng tư
  • Nếu nó phải được truy cập, chúng tôi làm cho nó có thể truy cập được dưới dạng thuộc tính công khai
  • Chúng tôi sẽ xác định nó là một thuộc tính riêng với thuộc tính tương ứng, khi và chỉ khi chúng tôi phải thực hiện một số kiểm tra hoặc chuyển đổi dữ liệu. [Ví dụ, bạn có thể xem lại lớp P của chúng tôi, trong đó thuộc tính phải nằm trong khoảng từ 0 đến 1000, được đảm bảo bởi thuộc tính "x"]
  • Ngoài ra, bạn có thể sử dụng trình thu thập và trình thiết lập, nhưng sử dụng thuộc tính là cách xử lý của Pythonic

Giả sử chúng ta đã định nghĩa "OurAtt" là thuộc tính công khai. Lớp học của chúng tôi đã được sử dụng thành công bởi những người dùng khác trong một thời gian dài

p1.set_x[47]
p1.set_x[p1.get_x[]+p2.get_x[]]
p1.get_x[]
0

ĐẦU RA

p1.set_x[47]
p1.set_x[p1.get_x[]+p2.get_x[]]
p1.get_x[]
1

Bây giờ đến điểm khiến một số OOPistas truyền thống sợ hãi vì trí thông minh của họ. Hãy tưởng tượng "OurAtt" đã được sử dụng như một số nguyên. Bây giờ, lớp của chúng ta phải đảm bảo rằng "OurAtt" phải có giá trị từ 0 đến 1000? . Do tính chất nó dễ dàng. Chúng tôi tạo phiên bản thuộc tính của "OurAtt"

p1.set_x[47]
p1.set_x[p1.get_x[]+p2.get_x[]]
p1.get_x[]
2

ĐẦU RA

p1.set_x[47]
p1.set_x[p1.get_x[]+p2.get_x[]]
p1.get_x[]
1

Điều này thật tuyệt phải không? . Vì vậy, các thuộc tính không chỉ là sự thay thế cho getters và setters

Một cái gì đó khác mà bạn có thể đã nhận thấy. Đối với người dùng của một lớp, các thuộc tính giống hệt về mặt cú pháp với các thuộc tính thông thường

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.

Ý nghĩa của @property trong Python là gì?

Người trang trí @property . Cú pháp của hàm này là. property[fget=None, fset=None, fdel=None, doc=None] trong đó, fget là hàm lấy giá trị của thuộc tính. fset là chức năng để đặt giá trị của thuộc tính. a built-in function that creates and returns a property object. The syntax of this function is: property[fget=None, fset=None, fdel=None, doc=None] where, fget is function to get value of the attribute. fset is function to set value of the attribute.

Trình trang trí @property ở Django là gì?

@property decorator là một công cụ trang trí tích hợp sẵn trong Python, hữu ích trong việc xác định các thuộc tính một cách dễ dàng mà không cần gọi thủ công hàm sẵn có property[].

Trình thiết lập trong Python là gì?

Getters. Đây là các phương thức được sử dụng trong Lập trình hướng đối tượng [OOPS] giúp truy cập các thuộc tính riêng tư từ một lớp. người định cư. Đây là các phương thức được sử dụng trong tính năng OOPS giúp đặt giá trị cho các thuộc tính riêng tư trong một lớp .

Chủ Đề