[爆卦]python def意思是什麼?優點缺點精華區懶人包

為什麼這篇python def意思鄉民發文收入到精華區:因為在python def意思這個討論話題中,有許多相關的文章在討論,這篇最有參考價值!作者KSJ (阿真)看板Python標題[心得] 關於 function (def) 的 defau...


--前言

這文章標題不知道下的好不好
我也沒爬文 如果已有類似觀念 麻煩推文說一下
本來還想把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
DigiPrince:http://tinyurl.com/7r3w2y 11/15 17:31
KSJ:看來是只有我了 囧... 11/15 17:45
mathfeel:每次show_append()之后跑help(show_append)。有甚麼發現 11/15 18:10
KSJ:在idle下 show_append( 之後就破梗了 x=會越來越長XD 11/15 18:18
sbrhsieh:Python 中除了 global ...,其實是沒有 definition 的 11/15 20:41
sbrhsieh:這個例子改寫成 C++,不也是一樣的行為嗎? 11/15 23:21

是指說 在runtime才"執行"產生函式嗎@@?
說來殘愧... 我在c與c++寫函式的時候還沒用過default值...

在我初學oop觀念時碰到的是python而非c++
c++的 private public的觀念 或是宣告class的方式
相較於python都較令我難理解
例如c++ . -> 在python下都是 . 理解能力的需求就不一樣
不過當然在c++的程式碼上 可讀性也許不夠 但理解後觀念會更清楚吧

我覺得還是該弄懂c++的類別觀念與寫法 (也許先略懂指標吧...
很多python相關的套件 說明文件還是在c++下較完整 例如PyQt
要了解而使用 以免像我對python def的誤用

mikapauli:不要創造會改變外部物件的函式,就沒這個問題了w 11/16 01:19
mikapauli:一般都會先做適當的copy說 11/16 01:22

其實我還蠻常用把cls instance當做變數在函式(別的class裡的)內傳來傳去
大部份是讀取需要的資料
修改資料的話就直接用method了 (classinstance.method("資料"))
我覺得在函式中修改instance時用instance的method 感覺還ok說
所以我覺得創造修改外部物件的函式應該是需要的
不知道這觀念對不對...

而我是以為class def __init__(self, arg = another_instance_create) 時
會重新創造 default arg裡的東西
所以中招了XD (如1F的文件的 important部份)

sbrhsieh:哎呀,我搞錯了。寫成 C++ 在寫法上沒有等效... 11/16 12:23
kdjf:到python3就很好理解了, 因為function也是class 11/17 09:43

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

darkgerm:推~寫得好清楚~ 11/19 02:14
※ 編輯: KSJ 來自: 180.176.140.46 (11/19 16:28)
mikapauli:真的需要的話當然OK阿,只是一般函式是沒有side effect的 11/20 21:09

你可能也想看看

搜尋相關網站