作者ddavid (謊言接線生)
看板Python
標題Re: [問題] Class中有關input的疑問
時間Thu Apr 16 13:39:50 2020
※ 引述《jasonhsu14 (14號星期五的傑森)》之銘言:
: H1=Human1()
: print(H1.BMI())得到當初創建類別時的預設或輸入的數字
: print(H1.BMI(170,80))時,得到不一樣的結果
: 有想過直接在 def BMI(self, h=160, w=50)這樣去寫
: 但這樣又等於重複做了跟__init__一樣的事情
: 所以想詢問有無辦法讓BMI變成一個
: 不輸入的話就會根據最一開始創建類別的預設(或輸入)數值
: 但也可以讓BMI自己另外輸入想要的數字
忽然覺得想說的多了點,還是回文好了。雖然推文給了一個回答,但我覺得最好
還是從概念上來處理這個問題。
H1.BMI()
這寫法很直覺,就是得到H1這個實體本身的BMI,沒有問題。但是:
H1.BMI(170, 80)
請問你覺得這是什麼概念呢?叫H1這個人幫你算算170/80的人BMI是多少?
你可以發現,這兩個用法的概念是衝突的。前者把H1當作一個有BMI的實體,後
者卻只是一個計算BMI的計算器。
那麼我的建議是,應該把實體跟計算器的角色分開來。這個計算器誰來負責呢?
我認為是Human1 class本身,把計算方法定義成Human1的一個靜態方法。當我們要計
算任意一組資料的BMI時,我們呼叫:
Human1.cal_BMI(170, 80)
這個cal_BMI()可以定義為:
@classmethod
def cal_BMI(cls, h, w):
# 計算並return BMI
當我們要得知一個實體H1本身的BMI時,我們呼叫:
H1.BMI()
而這個BMI()則定義為:
def BMI(self):
return Human1.cal_BMI(self.h, self.w)
這樣,我們就既不需要在兩處處理default值(__init__跟BMI),也兼顧了code
的重用性,同時讓實體跟class本體的角色更明確。同時,也不需要寫煩人的邏輯來
判斷輸入值是什麼情況、要用內部值或外部值等等。
BMI要修改計算方式,我們只需要改動cal_BMI(),除非引入了其他參數或要改變
實體與類的計算連接方式(比如說,公開測量時的cal_BMI都是很公正的,但是要讓
每個人自報BMI時都故意低報一點,就像NBA球員偷偷高報身高XD)才會動到BMI()。
--
「可是妳......不是天使嗎?」
「天使?」她緩緩的轉過頭來,用悲傷的表情。「天使,只不過是神創造出來的
不死玩偶。」
「而神,也只不過是詛咒下的偽善使者。」
--星.幻.夢的傳說
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 111.248.150.42 (臺灣)
※ 文章網址: https://www.ptt.cc/bbs/Python/M.1587015592.A.42B.html
※ 編輯: ddavid (111.248.150.42 臺灣), 04/16/2020 13:43:12
推 cuteSquirrel: 推 04/16 13:46
→ jasonhsu14: 謝謝你的回答,現在才看到XD 04/16 13:53
推 drysor: 推 04/16 15:32
推 a0956072892: 推個 04/16 15:43
推 s860134: 物件導向 04/17 20:03
推 TuCH: 想問一下用Human1.cal_BMI 還是 self.cal_BMI 比較好呢 04/19 16:40
我認為選擇 Human1.cal_BMI 比較好。概念上也就是說,這邊是每個人都依循這
個人類定義的標準計算方式給出BMI,他們不是「每個人用自己的方式計算」,所以
call的是類別靜態版本較符合這概念。
單從程式語言寫作而言也是建議如此做,即便Python確實可以讓你透過實體去呼
叫靜態方法。
※ 編輯: ddavid (114.36.173.238 臺灣), 04/19/2020 19:52:12
→ stucode: 我有不同的看法,在這個例子中 BMI 的計算並無涉及類別或 04/19 23:32
→ stucode: 類別變數,因此 cal_BMI() 應該寫成純函數比較合適。如果 04/19 23:32
→ stucode: 想把它放進 Human1 類別裡,用 @staticmethod 會是比較好 04/19 23:32
→ stucode: 的做法。假如想保留彈性空間,例如你覺得未來有個 04/19 23:33
→ stucode: 「新人類」類別會繼承自 Human1,而這個新類別的 BMI 04/19 23:33
→ stucode: 計算會參考到類別變數,所以使用 @classmethod 的話, 04/19 23:33
→ stucode: 呼叫部分應寫成 self.cal_BMI() 才能讓方法覆載正確發揮 04/19 23:33
→ stucode: 作用。寫成 Human1.cal_BMI() 的話反而會鎖死在基礎類別 04/19 23:34
其實我確實是有想過一些不同使用情境或未來擴展會導致應該使用不同設計的情
況。
不過我認為就這個例子可以單純化,所以就只給了基本的簡單設計。
基本上我認為與其過度設計不如等用到了再refactoring,工作上有深刻體驗。
所以事實上在原Po一開始那篇直接硬用if解決的方式,也未必有什麼不好。
至於你提到@staticmethod來取代@classmethod,你是對的。我不是為了擴展性
,只是直覺用了@classmethod,但其實這邊沒有必要使用cls,所以@staticmethod確
實比較好XD
※ 編輯: ddavid (1.160.87.162 臺灣), 04/20/2020 12:46:07
推 Arescrow: 推 04/20 15:21
推 stucode: 補個推 04/20 22:35