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/cn.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灯, 水草

请输入看板名称,例如:e-shopping站内搜寻

TOP