Python 板


LINE

※ 引述《littrabble (littrabble)》之銘言: : @property : def name(self): : return self._name : @name.setter : def name(self, new_name): : self._name = new_name : 然後可以使用 instance p, : p.name 取值, p.name = 1 設值 : 我的疑問是, : 1. 這根本無法保護變數,為什麼教程還要說這種寫法保護變數 : 2. 加那個@property @name.setter, 到底有什麼好處? : 我如果不使用@property, 而是把方法名稱改成 get_name, 跟 set_name 程式碼讀起來,不是更清楚明白嗎? : 有沒有很有經驗的大大,能幫我解惑一下 : 感恩 我們從幾個角度來思考這個問題: 1. 語感 當我們使用 class Human 時,在普遍的語感上,屬性或成員是一些這個 class 實例具有的狀態或資訊: human1 = Human(...) print(human1.name) # 印出 human1 的 名字 而方法在語感上是一些行為或動作: human1.dance() # 讓 human1 進行 跳舞 這個行為 那我們來思考一下,如果我們採用 get_name,那印出姓名會是這樣的語感: print(human1.get_name()) # 讓 human1 進行 取得自己姓名 這個行為,然後印出 # 這個行為的結果 比較一下兩種印出名字的語感,是不是採用屬性或成員比較自然、不拐彎抹角? 然而,這也不代表 get/set method 形式就要完全捨棄。在 PEP 8 中有提到相 關的建議。 首先,如果是超級單純的直接成員存取,也沒有特殊的限制邏輯考量,則你應該 乾脆地直接使用公開成員,什麼 @property 或 get/set method 都免了。 再來,如果這個邏輯變得複雜,我們隨時都可以使用 @property 進行包裝,讓 使用方式跟公開成員完全相同,但內部處理邏輯改變。 但是,使用 @property 的情況下,因為其語感給使用者就像是直接存取一個成 員變數,所以我們會希望就算它有包裝一些處理邏輯,但這些處理邏輯不要帶來副作 用,也不要是太過昂貴的操作,因為使用者不會設想一個簡單的: human1.name = "ddavid" 操作背後居然會導致他的銀行帳戶變成我的,或者要執行三天只因為真的去跑戶 政事務所改名流程。當你真的想要讓上面兩件事情發生,使用 method 來表現的語感 就更為合適: human1.set_bank_account_name("ddavid") human1.set_id_card_name("ddavid") 法律小提示:銀行帳戶沒法轉讓啦,所以放心吧。直接轉帳給我就好啦(誤) 以下是 PEP 8 相關原文: For simple public data attributes, it is best to expose just the attribute name, without complicated accessor/mutator methods. Keep in mind that Python provides an easy path to future enhancement, should you find that a simple data attribute needs to grow functional behavior. In that case, use properties to hide functional implementation behind simple data attribute access syntax. Note 1: Try to keep the functional behavior side-effect free, although side-effects such as caching are generally fine. Note 2: Avoid using properties for computationally expensive operations; the attribute notation makes the caller believe that access is (relatively) cheap. 2. 保護變數 原 po 可能誤解的一點是,@property 的保護變數是跟直接暴露成員相比的。在 保護變數這一點上,它跟 set/get method 效果相差不大。 比如相較於: class Human: def __init__(height: float): self.height = height human1 = Human(170.1) human1.height = -1 # 亂給身高為負值 使用以下方法可以對此做出保護: class Human: def __init__(self, height: float): self._height = height @property def height(self): return self._height @height.setter def height(self, value: float): if value < 0: raise ValueError("Height cannot be negative") self._height = value 當然你一樣可以用 set_height 的寫法做到這一點: def set_height(self, value: float): if value < 0: raise ValueError("Height cannot be negative") self._height = value 但當考量到前述的語感理由,在 height 是個單純屬性處理的情況下,就沒什麼 必要強調操作性。 同時,我們也可以拿掉 setter/getter 其中之一,讓其變成可讀不可寫或可寫 不可讀,這也是一種保護。 當然我們知道,即便使用 _ 甚至 __ 前綴的成員,在 Python 中始終有手段直 接操作原始成員,因為 Python 把這些判斷留給 programmer。 3. 封裝邏輯 比如說,對於人類而言,BMI 語感上作為一個很單純的屬性值也很直覺。可是當 我們已經存了身高體重,額外存一個 BMI 好像在某些情況下有點多餘。於是我們就 可以在維持其屬性語感的前提下把邏輯包裝起來: class Human: def __init__(self, height: float, weight: float): self.height = height self.weight = weight @property def bmi(self): return self.weight / (self.height * self.height) 所以這麼做後,我們就可以用 human1.bmi 這樣直覺的方式取得這個人的 BMI, 而且在身高體重有變化時還可以自然跟著變化。而因為這不是很昂貴的運算,所以每 次取都算一下也沒太大關係。 同時,因為我們沒有給予 setter,也表達出了對於這個值的保護是唯讀的,我 們不能手改 BMI 或想藉由改 BMI 去影響身高體重值之類。 如前述,如果語感上要強調 BMI 每次都是計算出來的,我認為寫成 get_bmi 的 方法也無不可。 -- 「可是妳......不是天使嗎?」 「天使?」她緩緩的轉過頭來,用悲傷的表情。「天使,只不過是神創造出來的 不死玩偶。」 「而神,也只不過是詛咒下的偽善使者。」 --星.幻.夢的傳說 --



※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 125.229.62.213 (臺灣)
※ 文章網址: https://webptt.com/m.aspx?n=bbs/Python/M.1736913822.A.4BF.html ※ 編輯: ddavid (125.229.62.213 臺灣), 01/15/2025 14:32:22
1F:推 sating00: 就…如果你寫的code也不是什麼大型專案,沒必要這樣設 01/15 20:23
2F:→ sating00: 計這些保護,除非設計理念跟有哲學上的潔癖(像我) 01/15 20:23
這倒不完全跟專案大小有關,跟系統是否接觸外部或者有其他協作者比較有關。
3F:推 melancholy07: 討論推 01/15 21:01
※ 編輯: ddavid (125.229.62.213 臺灣), 01/16/2025 10:46:49
4F:→ leolarrel: 我跟一樓一樣,寫程式有潔癖 01/16 11:41
5F:推 cuteSquirrel: 獅子習慣良好 01/17 07:33
6F:→ mantour: 但這樣的寫法使用者可能會以為自己在單純的賦值和取值, 01/18 17:29
7F:→ mantour: 等到出錯才會意識到這不是一個單純的屬性,用getter/set 01/18 17:29
8F:→ mantour: ter明示不是比較不容易誤解嗎。 01/18 17:29
9F:→ Hsins: 在使用物件時,沒有經過 @property 裝飾器修飾的,無法這樣 01/18 18:07
10F:→ Hsins: 操作;為了實現物件導向程式開發的封裝概念,本來也不應該 01/18 18:07
11F:→ Hsins: 在 class 以外直接操作屬性。所以如果產生「我不知道是在直 01/18 18:07
12F:→ Hsins: 接操作屬性還是使用 getter 或 setter 耶」這樣的想法,需 01/18 18:07
13F:→ Hsins: 要回來想想看審視一下當下的寫法有沒有問題。 01/18 18:07
14F:→ Hsins: 我上面說的可能有些繞口,簡單來說就是在 OOP 的理念中,屬 01/18 18:09
15F:→ Hsins: 性本來就不該被直接操作。 01/18 18:09
16F:推 ck574b027: 我試著比樓上更精確些。有封裝的概念時, 01/18 23:30
17F:→ ck574b027: 我沒給的,外人本來就不能要;外人能拿到的代表有控制 01/18 23:32
所以 PEP 8 才會強調不應該帶有副作用,基本概念就是保持使用者把它當直接 的屬性操作不會誤解出事。比如說作者只是加了一堆型別檢查、型別轉換、範圍檢查 等等,都通過了以後最後還是簡單的直接賦值,那就不用擔心使用者理解錯誤。 事實上大概就是 Pydantic 之類做的事情。 又或是你內部存公尺,但允許使用者用英呎存取,這只是很簡單的轉換。 還有像 requests 裡面呼叫 API 回應的 Response.ok: @property def ok(self): """Returns True if :attr:`status_code` is less than 400, False if not. This attribute checks if the status code of the response is between 400 and 600 to see if there was a client error or a server error. If the status code is between 200 and 400, this will return True. This is **not** a check to see if the response code is ``200 OK``. """ try: self.raise_for_status() except HTTPError: return False return True 它確實不是單純的取值,但概念很單純,雖然 raise_for_status() 裡面其實多 做了一些事情,但沒有會影響狀態的東西,所以也沒太大問題。 ※ 編輯: ddavid (114.44.6.70 臺灣), 01/28/2025 06:39:06
18F:→ w0005151: 純個人經驗來說,不是在開發lib或框架,真的沒必要用 01/31 00:10
19F:→ w0005151: 大部分時候遵守KISS原則帶來的好處勝於一切 01/31 00:11







like.gif 您可能會有興趣的文章
icon.png[問題/行為] 貓晚上進房間會不會有憋尿問題
icon.pngRe: [閒聊] 選了錯誤的女孩成為魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一張
icon.png[心得] EMS高領長版毛衣.墨小樓MC1002
icon.png[分享] 丹龍隔熱紙GE55+33+22
icon.png[問題] 清洗洗衣機
icon.png[尋物] 窗台下的空間
icon.png[閒聊] 双極の女神1 木魔爵
icon.png[售車] 新竹 1997 march 1297cc 白色 四門
icon.png[討論] 能從照片感受到攝影者心情嗎
icon.png[狂賀] 賀賀賀賀 賀!島村卯月!總選舉NO.1
icon.png[難過] 羨慕白皮膚的女生
icon.png閱讀文章
icon.png[黑特]
icon.png[問題] SBK S1安裝於安全帽位置
icon.png[分享] 舊woo100絕版開箱!!
icon.pngRe: [無言] 關於小包衛生紙
icon.png[開箱] E5-2683V3 RX480Strix 快睿C1 簡單測試
icon.png[心得] 蒼の海賊龍 地獄 執行者16PT
icon.png[售車] 1999年Virage iO 1.8EXi
icon.png[心得] 挑戰33 LV10 獅子座pt solo
icon.png[閒聊] 手把手教你不被桶之新手主購教學
icon.png[分享] Civic Type R 量產版官方照無預警流出
icon.png[售車] Golf 4 2.0 銀色 自排
icon.png[出售] Graco提籃汽座(有底座)2000元誠可議
icon.png[問題] 請問補牙材質掉了還能再補嗎?(台中半年內
icon.png[問題] 44th 單曲 生寫竟然都給重複的啊啊!
icon.png[心得] 華南紅卡/icash 核卡
icon.png[問題] 拔牙矯正這樣正常嗎
icon.png[贈送] 老莫高業 初業 102年版
icon.png[情報] 三大行動支付 本季掀戰火
icon.png[寶寶] 博客來Amos水蠟筆5/1特價五折
icon.pngRe: [心得] 新鮮人一些面試分享
icon.png[心得] 蒼の海賊龍 地獄 麒麟25PT
icon.pngRe: [閒聊] (君の名は。雷慎入) 君名二創漫畫翻譯
icon.pngRe: [閒聊] OGN中場影片:失蹤人口局 (英文字幕)
icon.png[問題] 台灣大哥大4G訊號差
icon.png[出售] [全國]全新千尋侘草LED燈, 水草

請輸入看板名稱,例如:Soft_Job站內搜尋

TOP