Python 板


LINE

※ 引述《ar0n77777 (property)》之铭言: : 各位前辈好 新年快乐 : 这是关於《精通python》上的疑问 : 想请问 class 中 @property 的使用 : @property 这个 decorator 是在其他地方已经被定义了吗 : 不能理解为何可以直接使用这个语法糖 是的 : 还有@property和@name.setter摆放位置的意义 : https://i.imgur.com/fGr96ny.jpg : 另外就是不能理解property的实际功效和用途 : 麻烦各位了... 非常感谢!! 直接看 decorator 会很像 magic, 我们慢慢来 首先考虑这样一个 class class Duck: def __init__(self, name): self.name = name 这没什麽好解释的, 你可以很方便操作这个 attribute >>> duck = Duck('Donald') >>> duck.name 'Donald' >>> duck.name = 'Daffy' >>> duck.name 'Daffy' 但过了一阵子, 可能你需要在修改鸭子名字时, 同时做某些其他事情 例如确认名字一定是字串, 而且不能超过 100 字之类的 所以你就把 class 改写成这样 class Duck: def __init__(self, name): self._name = name def get_name(self): return self._name def set_name(self, name): if not isinstance(name, str) or len(name) > 100: raise ValueError(name) self._name = name 然後叫大家用 get_name() 与 set_name(), 而不要用本来的 name 但是 1. 一定会有忘记的时候, 2. 原本有的程式都要重写很麻烦 所以这里就是 property 出场的时机 property 是一个内建的 Python 型别 (和 list set 等等类似) 但这个型别特别的地方是应用了一个叫 descriptor 的概念 要从实作细节讲起会花一千字以上, 所以这里就直接看范例与最後结果 class Duck: def __init__(self, name): self._name = name def get_name(self): return self._name def set_name(self, name): if not isinstance(name, str) or len(name) > 100: raise ValueError(name) self._name = name name = property(get_name, set_name) 在 Duck 上宣告叫 name 的 property, 然後把 get_name 与 set_name 传给它 这个 property 在 Python 里有四种被使用的方法 >>> duck.name # 取值 >>> duck.name = ... # 赋值 >>> del duck.name # 删值 >>> help(duck.name) # 看文件 如果 duck.name 是一个正常普通的值 (例如最开始的那个版本) 上面动作会发生的事情很直观, 你应该也知道 但是如果 name 是一个 descriptor, 则 Python 会去触发它上面的对应 method 取值触发 __get__, 赋值触发 __set__, 其余类推 所以当你取值时, 会发生这样的事情: 1. 你呼叫 duck.name 2. Python 呼叫 duck.name.__get__() -> 会回传一个值 3. Python 把这个值当作 duck.name 的回传值, 把它送给你 赋值则是这样: 1. 你把 'Duffy' 赋给 duck.name 2. Python 不会取代 duck.name, 而是呼叫 duck.name.__set__('Duffy') 回到 property, 这个 class 的实作大致包含下面这样: class property: def __init__(self, fget=None, fset=None, fdel=None, doc=None): self.fget = fget # 後面都一样所以略过 def __get__(self, obj): return self.fget(obj) # 其他实作差不多, 略过 所以当你呼叫 duck.name 时, 大致会发生这样的事情 1. duck.name 2. duck.name.__get__() 3. Duck.name.__get__(duck) [#1] 4. Duck.name.fget(duck) 5. Duck.get_name(duck) 因为我们把 get_name 传进去了 6. 得到结果 [#1]: 刚好前几篇才提到, 呼叫 instance.method() 等於 Class.method(instance) 这边的状况类似 (有微妙的不同), Python 会自动转换呼叫的格式 注意 5. 等同於 duck.get_name() 所以结果就等於呼叫 property 的第一参数 以上就是 property 的简单原理 但是这样写起来还是有点麻烦, 而且更重要的是, 不直观 当你想知道 duck.name 时, 会需要先发现 name 是一个 property 再根据 property 的引数知道对应传进去的函式, 再去找函式实作, 不太方便 Decorator 就是想办法把这个 property 呼叫变得更简明 当你在一个 method 上加上 @property 时, 例如这样: class Duck: # 略 @property def name(self): return self._name Python 会做以下的事情: 1. 根据 method 名 (这里就是 name) 用一个同名 property 替代掉 2. 被替代掉的函式就当作该 property 的 fget 引数 3. property 的 doc 引数就是原本 getter 的 docstring 类似地, property.setter 会把被装饰的函式设成该 property 的 setter 所以下面的实作 class Duck: @property def name(self): return self._name @name.setter def name(self, name): # 顺带一提其实这个函式叫什麽根本不重要 self._name = name 大致等於 class Duck: def getname(self): return self._name # @property 的作用 name = property(fget=getname, doc=getname.__doc__) del getname def setname(self, value): self._name = name # @name.setter 的作用 name.fset = setname del setname 实际上因为 decorator 本身可以在赋名之前就作用 所以可以取和 property 一样的名字 但是要讨论这个就又要一千字, 所以这里就不讲到那里 如果有兴趣的话可以自己当成未来课题慢慢研究 另外从上面可以看到, property class 还有一个 deleter 可以设 所以实际上也还有一个 @property.deleter, 只是比较不常用 甚至实务上其实最常见的实作也只会用到 getter 而已 当你用到 setter 其实常常就代表需要重构了 --
1F:→ GNUGCC:void main(void) 的写法是可行的唷^^08/10 00:59
2F:→ GNUGCC:虽然这个写法较传统,但是语法与文法都正确哦^^08/10 02:16
3F:→ GNUGCC:目前我使用的 Visual C++ 都接受 void main(void) 与 08/10 20:18
4F:→ GNUGCC:int main(void),各位可以把 C++ 专案改成原生 C++ 类型来 08/10 20:19
5F:→ GNUGCC:用 void main(void) 来写发现也可通过编译. 08/10 20:21
6F:→ GNUGCC:这个就是 Visual C++ 的弹性.08/11 20:23
--



※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 218.161.94.175
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/Python/M.1514825287.A.BEE.html
7F:推 ar0n77777: 大致上理解了,感谢u大解答!!太感谢了 01/02 01:20
8F:推 aszx4510: 感谢教学 01/02 06:22
9F:推 billy4195: 推个 01/02 07:13
10F:→ timTan: 又帅又清楚,推推推 01/04 12:23
11F:推 henry8168: 用心推推 01/04 12:27
12F:推 fantasymaker: 推 01/05 16:34
13F:推 twtkacc: 推 01/07 02:32
14F:推 befdawn: 推 04/04 01:06
15F:推 alan23273850: 年尾才看到有学习到给推 12/16 03:15
16F:推 Philethan: WOW 02/02 23:53







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

请输入看板名称,例如:Gossiping站内搜寻

TOP