作者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://webptt.com/cn.aspx?n=bbs/Python/M.1587015592.A.42B.html
※ 编辑: ddavid (111.248.150.42 台湾), 04/16/2020 13:43:12
1F:推 cuteSquirrel: 推 04/16 13:46
2F:→ jasonhsu14: 谢谢你的回答,现在才看到XD 04/16 13:53
3F:推 drysor: 推 04/16 15:32
4F:推 a0956072892: 推个 04/16 15:43
5F:推 s860134: 物件导向 04/17 20:03
6F:推 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
7F:→ stucode: 我有不同的看法,在这个例子中 BMI 的计算并无涉及类别或 04/19 23:32
8F:→ stucode: 类别变数,因此 cal_BMI() 应该写成纯函数比较合适。如果 04/19 23:32
9F:→ stucode: 想把它放进 Human1 类别里,用 @staticmethod 会是比较好 04/19 23:32
10F:→ stucode: 的做法。假如想保留弹性空间,例如你觉得未来有个 04/19 23:33
11F:→ stucode: 「新人类」类别会继承自 Human1,而这个新类别的 BMI 04/19 23:33
12F:→ stucode: 计算会参考到类别变数,所以使用 @classmethod 的话, 04/19 23:33
13F:→ stucode: 呼叫部分应写成 self.cal_BMI() 才能让方法覆载正确发挥 04/19 23:33
14F:→ 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
15F:推 Arescrow: 推 04/20 15:21
16F:推 stucode: 补个推 04/20 22:35