Re: [問題] Django 的 @property

看板Python作者 (迅雷不及掩耳盜鈴)時間5年前 (2020/02/03 02:59), 編輯推噓6(6012)
留言18則, 4人參與, 5年前最新討論串1/1
這件事情要從物件導向先開始說起。 在物件導向程式設計(Object-Oriented Programming)的理念下,我們將原本在 程序式程式設計(Procedural Programming) 中的變數和函數對應到物件的屬性 與方法,宣告類別作為實例物件的基礎,以此達到封裝(Encapsulation)、繼承 (Inhertitance)和多型(polymorphism)這三大物件導向的特性。 這裡暫且不 提其他內容,先聊聊封裝這件事: --- 在物件導向程式設計方法中,封裝是指,一種將抽象性函式介面的實作細節 部份包裝、隱藏起來的方法。同時,它也是一種防止外界呼叫端,去存取物 件內部實作細節的手段,這個手段是由程式語言本身來提供的。 --- 簡單來說,一個類別在定義時可以決定自己所屬的屬性和方法是否能夠被其他類 別所使用。在 Java 中,開發者習慣撰寫所謂的 settergetter 來對類別下 的私有屬性進行取值和賦值(或更新)的操作,在 Python 中可能會寫成這樣: ```python class MyClass: def __init__(self, value): self._value = value def get_value(self): return self._value def set_value(self, value): self._value = value # create the object my_object = MyClass(100) # get the value print(my_object.get_value()) # set the value my_object.set_value(200) ``` 只是這樣寫起來不夠 Pythonic,所以在 Python 2.2 之後新增了 @property 這 個裝飾器,讓開發者可以直接存取類別的屬性,而在需要時又可以如同使用一般 公開屬性一樣地對私有屬性進行訪問與修改: ```python class MyClass: def __init__(self, value): self._value = value @property def value(self): return self._value @value.setter def set_value(self, value): self._value = value # create the object my_object = MyClass(100) # get the value print(my_object.value) # set the value my_object.value = 200 ``` 這樣一來在使用起來就不用呼叫 getter 和 setter 而是採用很直觀的點操作符 來存取物件的屬性,但實際上這個屬性仍然是私有的(不過其實 Python 中的屬 性嚴格說起來並不私有... )。然而雖然取得屬性值與設定值時的作法看起來是 一樣的,但他其實是調用你所定義的不同方法,只是透過 @property 這個裝飾 器來實現這樣的結果※ 引述《Philethan (Ethan)》之銘言: : 大家好,小弟大概知道 @property 有助於日後修改 class 的參數條件限制, : 例如幾個月前我定義了球類(class Ball),接著我建立了數十顆球,現在才 : 想起我忘記強調它的半徑必須大於零,所以倘若還要制定一個 set_radius() : 來限制半徑,那麼我得回去將所有 ball.radius = 10 之類的程式碼都修改為 : ball.set_radius(10),這會很麻煩,所以就有了 @property 這種東西出來。 : 不過我不知道怎麼將上述我對 @property 的理解,應用在底下 Django 中QQ : 我正在讀 "Django Tutorial Part 8: User authentication and permissions" : https://reurl.cc/xD5g8E : 其中有一段程式碼為(https://i.imgur.com/HMcdolW.png
): : @property : def is_overdue(self): : if self.due_back and date.today() > self.due_back: : return True : return False : 就我理解,這段程式碼的用意在於檢查「書籍借閱是否已過期」,所以總覺得 : 如果我拿掉 @property,好像也有相同效果?(測試結果:拿掉 @property 後, : 確實看不出有什麼異樣)。另外,這裡似乎也沒有修改資料庫中的任何資料, : 所以我就也無法用上述的「球半徑的例子」來理解這裡的 @property 用途 QQ : 另外,我有在 StackOverflow 查到: : "What the @property decorator does, is declare that : it can be accessed like it's a regular property." : https://stackoverflow.com/questions/58558989/what-does-djangos-property-do : 但我還是不太懂 QQ : 還請各位大大協助,謝謝您們! -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 140.112.247.1 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/Python/M.1580669992.A.EF4.html

02/03 09:59, 5年前 , 1F
@O@ 未看先推!!
02/03 09:59, 1F

02/03 10:06, 5年前 , 2F
這讓我想起,我好像有在 python docs(?) 看到其實"取值
02/03 10:06, 2F

02/03 10:07, 5年前 , 3F
"(點操作)並不是直接取,而是會先檢查有沒有定義
02/03 10:07, 3F

02/03 10:07, 5年前 , 4F
__get__ 與 __set__,有的話那就用(就是property),
02/03 10:07, 4F

02/03 10:08, 5年前 , 5F
沒有的話就直接取,找它的 class member
02/03 10:08, 5F

02/03 10:09, 5年前 , 6F
所以,若在 def is_overdue(self) 前加上 @property
02/03 10:09, 6F

02/03 10:09, 5年前 , 7F
那麼就可以更 pythonic,把 is_overdue() 函數看成
02/03 10:09, 7F

02/03 10:10, 5年前 , 8F
一種變數,應該是這意思囉?感謝大大教學~~
02/03 10:10, 8F

02/03 10:10, 5年前 , 9F
雖然總覺得這種"把函數看成變數"的背後機制,似乎跟
02/03 10:10, 9F

02/03 10:10, 5年前 , 10F
剛才提的"先檢查有沒有定義__get__與__set__"不太一樣
02/03 10:10, 10F

02/03 10:14, 5年前 , 11F
哦哦我在 python docs 看到了!
02/03 10:14, 11F

02/03 10:15, 5年前 , 12F
The @property decorator turns the .... method into
02/03 10:15, 12F

02/03 10:15, 5年前 , 13F
a "getter" for a read-only attribute with the same
02/03 10:15, 13F

02/03 10:17, 5年前 , 14F
02/03 10:17, 14F

02/03 10:17, 5年前 , 15F
02/03 10:17, 15F

02/03 21:46, 5年前 , 16F
push
02/03 21:46, 16F

02/06 02:16, 5年前 , 17F
推個
02/06 02:16, 17F

02/21 18:02, 5年前 , 18F
推個~
02/21 18:02, 18F
文章代碼(AID): #1UDnmexq (Python)
文章代碼(AID): #1UDnmexq (Python)