[心得] 關於 function (def) 的 default...

看板Python作者 (阿真)時間13年前 (2011/11/15 09:20), 編輯推噓5(507)
留言12則, 7人參與, 最新討論串1/1
--前言 這文章標題不知道下的好不好 我也沒爬文 如果已有類似觀念 麻煩推文說一下 本來還想把python原文書賣掉 發生這件人為bug後 還是留起來吧XD --內容 這是個關於定義函式時 給定預設值 與 mutable object 的概念 為了簡化實際的案件 下面是一個例子 def show_append(x=[],y=2): x.append(y) print x 寫成這樣... 本來的意思是希望 show_append函式裡的二個變數 x 是個有 append method 的 object y是被 append 的值 如果都沒給值的話 就來個範例 空的list 與 被加入的數2 但很多事情總是不如想像... 下面來三個範例 >>> show_append() [2] >>> show_append() [2, 2] >>> show_append() [2, 2, 2] 這...這飯粒...有毒 跟預想的不一樣 原因是: 在定義函式中 預設的變數(x跟y) 是在定義函式執行時所產生(不是在呼叫的時候) 所以 x (也就是[])是在定義show_append函式時 就一直存在的東西 而因為[] 是mutable obj 在使用 append 這個in-place change的方法時 本身就會改變 所以 要範例的話 可以如下 >>> show_append([]) [2] 給個新的"[]" 就行了 順帶一提 >>> show_append() [2, 2, 2, 2, 2] 原來的預設值還在喲~ 順帶再提 也許你可能會這樣想 如果給x一個新的值[]行不行 像下面 >>> show_append(x=[]) [2] x的預設直就變成空的[]了~?? 當然是不行... 否則假使你用 show_append (y=3) 以後不就都append 3了?(又違反意思了) 在定義函式裡 使用的預設值 比方 def func(name = value_d): ... 呼叫func(name = value) 並不是創建name,並給一個新的值value 所以你不能在呼叫show_append時創建新的變數 像 show_append(another_value = 99) 呼叫時用的name 只是拿來對應func裡的name用而已 (找名字) 預設的value_d值仍然存在 所以 >>> show_append() [2, 2, 2, 2, 2, 2] 一個也沒少喲~ --結論 要注意給函式的預設值是否為mutable,是否符合創造函式的原意 記住python這樣的特性 運用在該用的地方吧!! 記得 力量越大 bug也越大... 共de之 --題外話 總覺得不會碰上的事 總是會碰上...orz 當這樣的問題發生在class裡頭的__init__時候 就更難發現了(我這是這種) 希望不要跟我犯一樣的錯...(還是只有我... 以上 歡迎指正與分享 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 140.112.63.202

11/15 17:31, , 1F

11/15 17:45, , 2F
看來是只有我了 囧...
11/15 17:45, 2F

11/15 18:10, , 3F
每次show_append()之后跑help(show_append)。有甚麼發現
11/15 18:10, 3F

11/15 18:18, , 4F
在idle下 show_append( 之後就破梗了 x=會越來越長XD
11/15 18:18, 4F

11/15 20:41, , 5F
Python 中除了 global ...,其實是沒有 definition 的
11/15 20:41, 5F

11/15 23:21, , 6F
這個例子改寫成 C++,不也是一樣的行為嗎?
11/15 23:21, 6F
是指說 在runtime才"執行"產生函式嗎@@? 說來殘愧... 我在c與c++寫函式的時候還沒用過default值... 在我初學oop觀念時碰到的是python而非c++ c++的 private public的觀念 或是宣告class的方式 相較於python都較令我難理解 例如c++ . -> 在python下都是 . 理解能力的需求就不一樣 不過當然在c++的程式碼上 可讀性也許不夠 但理解後觀念會更清楚吧 我覺得還是該弄懂c++的類別觀念與寫法 (也許先略懂指標吧... 很多python相關的套件 說明文件還是在c++下較完整 例如PyQt 要了解而使用 以免像我對python def的誤用

11/16 01:19, , 7F
不要創造會改變外部物件的函式,就沒這個問題了w
11/16 01:19, 7F

11/16 01:22, , 8F
一般都會先做適當的copy說
11/16 01:22, 8F
其實我還蠻常用把cls instance當做變數在函式(別的class裡的)內傳來傳去 大部份是讀取需要的資料 修改資料的話就直接用method了 (classinstance.method("資料")) 我覺得在函式中修改instance時用instance的method 感覺還ok說 所以我覺得創造修改外部物件的函式應該是需要的 不知道這觀念對不對... 而我是以為class def __init__(self, arg = another_instance_create) 時 會重新創造 default arg裡的東西 所以中招了XD (如1F的文件的 important部份)

11/16 12:23, , 9F
哎呀,我搞錯了。寫成 C++ 在寫法上沒有等效...
11/16 12:23, 9F

11/17 09:43, , 10F
到python3就很好理解了, 因為function也是class
11/17 09:43, 10F
我參考的原文書裡有提了許多 3與2不同的地方 print, string type, type & class, range 等等 不知道function的修改呢~ 有空再來看看:) (這讓我想到 剛學python就抓3下來因為print變成func而無法helloworld的一段往事) 不過我目前使用的相關套件在2下仍有比較好的支援度 所以3還可以再緩一下吧 (我目前是用python2.5較多)

11/19 02:14, , 11F
推~寫得好清楚~
11/19 02:14, 11F
※ 編輯: KSJ 來自: 180.176.140.46 (11/19 16:28)

11/20 21:09, , 12F
真的需要的話當然OK阿,只是一般函式是沒有side effect的
11/20 21:09, 12F
文章代碼(AID): #1EmYxwoc (Python)