Python 板


LINE

: 推 pmove: 回b大,你说的官方是出自: 04/02 09:29 : → pmove: https://docs.python.org/3.3/tutorial/controlflow.html 04/02 09:29 : → pmove: Important warning: The default value is evaluated only 04/02 09:30 : → pmove: 下一句就是:This makes a difference when the default is 04/02 09:30 : → pmove: a mutable object such as a list, dictionary, or 04/02 09:31 : → pmove: instances of most classes. 04/02 09:31 : → pmove: 里面就提到mutable object.你要觉得倒果为因,我也没办法 04/02 09:33 : 推 pmove: 我自己是觉得你跟我讲The default value is evaluated only 04/02 09:53 : → pmove: once" 我自己是没办法理解的,但是你告诉我哪些是mutable? 04/02 09:54 : → pmove: 哪些是immutable? mutable/immutable会有哪种情形?这样我 04/02 09:54 : → pmove: 比较好理解。所以才从mutable/immutable切入。 04/02 09:55 : 推 froce: 推楼上,这根本就不是bug,动态语言常这样设计 04/06 07:44 看推文似乎很多人分不清楚值(value)和表达式(expression) 举个例子 1 def connect_db(): 2 return ... 3 4 def work(db = connect_db()): 5 db.execute(...) 6 7 DB = connect_db() 8 work( DB ) 请问 connect_db() 会执行几次? 正常人类的思考: 嗯... work 函数需要 1 个叫做 db 参数,我也提供一个正确的值, 我不在乎有没有预设值, 反正我没用到, 那麽 connect_db() 应该只在第 7 行处执行了一次 但 Python 实际上会执行两次 第一次在第 4 行 第二次在第 7 行 这就是官方文档中 "The default values are evaluated at the point of function definition" 的意思 看到了吗? connect_db 的回传值是 mutable 或 immutable 跟本不重要 究其原因就只是 Python 的规格要求:参数的预设值於函数定义时计算 CPython 也只是照着规格书去实作而已 再举个例子, 这次预设值连型别都没有: 1 def check_missing(): 2 raise Exception("You missed one argument") 3 4 def work(db = check_missing()): 5 db.execute(...) 6 7 DB = connect_db() 8 work( DB ) 请问以上程式可否顺利执行? 正常人类: 当然可以 (事实上这就是很多动态语言检查「参数是否缺少」的作法) Python: 不行 (因为 check_missing() 在第 4 行就呼叫了) Traceback (most recent call last): File "test.py", line 4, in <module> def work(db = check_missing()): File "test.py", line 2, in check_missing raise Exception("You missed one argument") Exception: You missed one argument 你看, 我连函数都还没呼叫就挂了! 为什麽说这是个雷? 因为这个特性简直莫名奇妙, 完全反直觉, 也没有什麽好处. 有人说动态语言常这样设计, 纯属胡说八道 Javascript: function check_missing(){ throw "Error" } function work(db=check_missing()){ ... } work(db) 顺利执行 C++: int f(){ throw "error"; } int work(int data=f()){ return data; } int main(){ work(3); } 顺利执行 Ruby: def check_missing(number) raise 'An error has occured' end def work(data = check_missing() ) puts(data) end work(1) 顺利执行 PHP: 预设值只能使用字面常量(literals) Lua: 不支援预设值 Java: 不支援预设值 就我知道的语言中只有 Python 有这种设计, 它没有带来任何好处. 这还只是第一个雷而已. 让我们看第二个雷 "The default value is evaluated only once." 就是这个预设值不但会「超前计算」, 而且还会被 cache 住. 原po的问题就是这个特性造成的. 推文里一直说因为原po的预设值[]是mutable, 因此如何如何, 这里给一个 immutable 一样会雷到人的例子 1 import random 2 3 def func(a=random.random()): 4 return a 5 6 x = func() 7 y = func() 请问 x 和 y 会相等吗? 正常人类: 机率很小, 除非刚好两次随机抽到一样的数 Python : 保证 x,y 完全一样! 为什麽? 因为 Python 会把 random.random() 的值记录在 func.__defaults__ 里 所以你看到了, random.random() 的回传值 float 是 immutable 又如何? 还不是雷人. 雷就雷吧, 有什麽其他的好处吗? 抱歉, 只有特定场合需要建立变数的副本时很方便, 但这属於「歪打正着」和「先射箭再画靶」的劣招, 带来方便的同时带来更多混淆. 这两个雷就是设计缺陷, 没什麽好争的, 从 python 2 或更早以前就存在, Guido 本人也承认是设计缺陷 https://twitter.com/gvanrossum/status/1014524798850875393 正确的实作应该是「预设值仅在 函数呼叫且该参数被省略时 计算」 这是 Python 少数几个地雷之一, 小心并正确地避开就是了 官方建议「预设值不要用mutable object」也是如此用意. 但这是不够的, 你还要保证这个 default value 建立时没有其他「副作用」 另外 其实不建议初学者直接往所谓的「底层」去看, 那不是原因, 那只是实作而已. 就像写C++也不要没事就看组语, 写Java不要没事就去读bytecode 应先以更宏观角度理解现象的本质 你以为把「基础」研究透了, 实际上你只是研究了一个二十年前的错误而已, 甚至无法意识到这究竟是不是个错误. --



※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 172.103.227.117 (加拿大)
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/Python/M.1586154248.A.888.html ※ 编辑: bibo9901 (172.103.227.117 加拿大), 04/06/2020 14:25:17 ※ 编辑: bibo9901 (172.103.227.117 加拿大), 04/06/2020 14:59:30 ※ 编辑: bibo9901 (172.103.227.117 加拿大), 04/06/2020 14:59:59 ※ 编辑: bibo9901 (172.103.227.117 加拿大), 04/06/2020 15:01:07 ※ 编辑: bibo9901 (172.103.227.117 加拿大), 04/06/2020 15:02:11 ※ 编辑: bibo9901 (172.103.227.117 加拿大), 04/06/2020 15:13:05
1F:→ pmove: 第8行work(DB)可以拿掉,仍然会执行第4行根第7行两次 04/06 15:07
※ 编辑: bibo9901 (172.103.227.117 加拿大), 04/06/2020 15:14:05
2F:→ bibo9901: 我当然知道可以拿掉 我是以人类的角度写正常的程式 04/06 15:14
※ 编辑: bibo9901 (172.103.227.117 加拿大), 04/06/2020 15:17:53 ※ 编辑: bibo9901 (172.103.227.117 加拿大), 04/06/2020 15:19:28
3F:→ pmove: 你举例的情形是argument assign一个function, 04/06 15:39
※ 编辑: bibo9901 (172.103.227.117 加拿大), 04/06/2020 15:39:52
4F:→ pmove: function虽然会return值,但跟argument直接assign mutable/ 04/06 15:40
※ 编辑: bibo9901 (172.103.227.117 加拿大), 04/06/2020 15:40:43
5F:→ pmove: immutable时的情况,是不一样的。原Po是问assign None obje 04/06 15:41
6F:→ pmove: t, None object is a unique, immutable object. 04/06 15:41
※ 编辑: bibo9901 (172.103.227.117 加拿大), 04/06/2020 15:45:25
7F:→ bibo9901: 我哪有给一个function, 我是给function的回传值 OK? 04/06 15:47
8F:→ bibo9901: 原po的问题还结合了 variable scope 的问题 04/06 15:48
※ 编辑: bibo9901 (172.103.227.117 加拿大), 04/06/2020 15:50:36
9F:→ bibo9901: 难道random.random()就不是unique&immutable object XD 04/06 16:03
10F:→ bibo9901: 再说unique object是啥? 每个object都嘛unique.. 04/06 16:04
11F:→ pmove: Unique 是指None object的值只有None, 不像int可以有1 或者 04/06 16:31
12F:→ pmove: 4... 04/06 16:31
13F:→ pmove: 我觉得b大有点超译原po所要问的,只有我这样感觉吗? 04/06 16:46
14F:推 yushes920179: 我觉得你说的很好懂 不过有必要这麽派吗 04/07 08:33
15F:推 TuCH: 学到了 重点就是"参数的预设值於函数定义时计算" 04/07 15:57
16F:→ TuCH: 雷一跟雷二跟其他例子都是这个的延伸 04/07 15:59
17F:→ pmove: 补充一点,如果函数定义在缩排里面,但是此函数的参数直接 04/07 16:36
18F:→ pmove: 函数。那麽此参数就不会立刻有值了。 04/07 16:37
19F:推 Starcraft2: 推详细说明 04/09 01:54
20F:推 s860134: "参数的预设值於函数定义时计算" 重点 04/15 22:55
21F:→ s860134: 只要你预设值不要存值,存 function pointer 就解决了~ 04/15 22:57
22F:→ s860134: e.g. property, 或是 callable object 04/15 22:58
23F:→ s860134: 像本篇例子 check_missing 可以置换成一个有 __call__ 04/15 23:00
24F:→ s860134: 或 __getattr__ 的自定义 class 即可达成想要的效果 04/15 23:02







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