python的pass在函数中的作用_Pass Share:Python / Julia 中函数变量的传递机制
從 C / MATLAB 過來的同學注意!
Julia / Python 中使用的參數傳遞變量方式是不一樣的。(以C的眼光看)在語法上細微的差別就會產生完全不一樣的內容。(至少我被坑了很多次)。這篇文章的主要作用是逃坑以及方便各種從不同語言過來的人投奔我們Julia!/狗頭
變量的傳輸方式
對于從 C 和 MATLAB 中轉移過來的同學,必須非常注意的一個問題是Julia 中變量的傳輸機制是Python 黨最好跳過這一小節。
此處有兩個概念:values:真實的數據
variables: 變量名,在這個語境下我認為這個“名”字非常重要。在編程語言中,用變量名bind(鏈接)到 values
Pass and share 機制中,在傳遞的過程中values不會被復制。函數內部中產生了新的變量名。這些變量名
Example 1 & 2
PS: 這兩個例子必須連起來看!
y = [1 1]
function f!(z) # there is a "!" mark: see link Tip1 Tip2 below
z[1] = 2 * z[2]
z
# this function return z
end
f!(y)
# 1×2 Array{Int64,2}:
# 2 1
## guess what !!!!!
y
# 1×2 Array{Int64,2}:
# 2 1
這里變量y變化了!C和MATLAB的用戶看見會覺得這顛覆了當年我們對于函數穿參的根本守則。
原因是:y作為數組,是mutable(可變的)的。傳入的時候,實際上只是用z的refer to 一組數據,即y也refer to 的那一組。當我們去改動z[1],實際上是通過這個z變量名,找到了一組數據的第一個元素,并賦值為等號右面的結果。 所以,當我們用y來訪問數據時,自然數據是更改過的。
下面再來看一個例子
y = [1 1]
function g(z) # note that there is no ! here
z = 2*z
z
end
g(y)
# 1×2 Array{Int64,2}:
# 2 2
# guess what!
y
# 1×2 Array{Int64,2}:
# 1 1
這里的y又不變了。這里發生了什么?明明在函數g里,我們也改變了z。 這里似乎又顛覆了剛剛建立的認識。
為了說明到底發生了什么,我們做一個類比,把variables(變量名)比作標簽,values(真實的數據)比作物品。變量名就像一個標簽貼在了實際的物品(數據)上:傳入函數前,我們可以理解為,標簽y貼在一組數據value1上,value1的實際數值是[1 1]。
y作為參數傳入函數g后,此時只是多生成了一個標簽z,同樣貼在數據value1上。
z = 2*z的第一步:現在我們通過標簽z訪問value1,并且根據里面的內容計算2*z也就生成了一組新的數據,我們命名為value2。 這得到了我們右面的運算結果。
z = 2*z的第二步:把標簽z挪動位置,貼在value2上。
... (略)
上述的1-4過程進行完了以后,我們就可以看出來分別有value1, value2 對應標簽 y, z。y所貼著的數據value1從來沒有改變過。因此在此處y又不變了。
Excercise: 為了鞏固此處發生了什么,最好用標簽物品概念把上一個y改變的例子說明一下,并對比其中的不同。 并且把兩個例子串起來重新表述一遍。題外話:這個變化對我來說實際上非常不習慣,我寫過很長一段時間的C,后來寫過一段時間Python ,這個轉換可以說是狠狠坑我了一把,甚至直接導致了我相當不喜歡Python。現在有了一些鋪墊,我在 Julia 中已經基本適應了。
有人可能會說,這個機制 Julia 也用,Python 也用為什么你這樣吹 Julia 而討厭 Python 呢,說不定你先用Julia后會喜歡Python。答曰:我依然要吹Julia 。原因如下:1. 文檔標注:雖然Julia這一點上面使用了一樣的機制,Julia的官方文檔在非常顯眼的地方是詳細的寫了這一點的不同(Noteworthy Differences),而且在編程風格中甚至針對這一點進行了強烈的風格建議,以改良你的代碼,以防你寫和閱讀代碼的時候忘記了這一點,參閱: Tips 1,Tips 2。(個人偏好,并未引戰,只希望用Julia的人如果進入了這個坑,看了我這篇文章能熄滅你的怒火)。2. Julia 真的關心你的代碼效率,他是一門跟 C 進行性能比較的語言。
C 用戶可能會用“指針”來理解這個過程了。但可能出現一個疑惑了,這樣的代碼有危險。函數在C和數學中都給人一種“單向性”的感覺:輸入只是用來確定輸出的東西。輸入怎么能夠改變呢?C 中如果要完成類似的行為,需要顯式傳入“指針”。但是在Pass and Share機制下,即使不顯式傳入,也會把數據暴露在危險當中了!。
我只能承認這確實是我們需要承擔這樣的風險。(可能關于傳入參數這件事情可以有其他的理解方式嗎?請知友指教了)所以在Julia 的代碼風格(Tips 1)當中(不強制)建議道,當我們的函數有可能改變參數中的mutable變量時,我們需要尊崇convention在函數名中以!結尾,如Example 1。
在本小節最后,必須講一下如何才能寫出一個返回值與上述例子之中f!相同但是不改變輸入參數y的函數了,代碼如下:使用copy()
function f(w)
z = copy(x)
f!(z)
end
copy函數會生成一個新的數據,是(C的意義下的)真正的復制了一次變量。
實際上這里展示的寫法:寫一個f!,
再用一個f包裝起來,
在一些官方函數中有使用。個人覺得這種寫法巧妙的消解了Pass and Share 的機制帶來的違和感,非常美妙,保持一種微妙的博弈。如果說你想用Pass and Share 的特性更改輸入的參數,那就使用f!,如果你想要更保守一些f。
總結
以上是生活随笔為你收集整理的python的pass在函数中的作用_Pass Share:Python / Julia 中函数变量的传递机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 为什么用python写爬虫_零基础,是怎
- 下一篇: python编的俄罗斯方块游戏_pyth