python - ndarray in funcion 、passed by assignment 、 Augmented Assignment(+= vs -)

◎前置概念
◎Immutable and Mutable 
  • 若你傳遞了mutable object,在function裡,傳遞進來的object為原本object的引用,因此會影響到外部function(原本)的object。(範例 1)
  • 若你在function裡""更動(重新綁定)傳遞進來的mutable object的引用,外部function(原本)的object從你更動了引用後,將不再知道你對object的任何的運作。(範例 2)
  • 若你傳遞了immutable object,無法影響到外部function(原本)的object,也無法對object重新綁定引用。
◎一句話概括

  • 每次的 Assignment( = ),只是"創造"一個新的reference object,而不是(re-assign)更動object的reference

◎簡單範例

numpy.array為mutable type
  • 範例 1

def my_func(ar):
    ar[2] = 5
ar = np.zeros(4)
my_func(ar)
print (ar)
結果
[ 0.  0.  5.  0.]
  • 範例 2
def my_func(ar):
    ar[2] = 5
    #re-assign
    ar = np.array([1,1,1,1])
    ar[1] = 5
ar = np.zeros(4)
my_func(ar)
print (ar)
結果
[ 0.  0.  5.  0.]

◎進階範例


  • 我們都知道若在function內call global variable,會自動將值從global variable帶過來

ar = np.zeros(4)    
def my_func():
    print ("in-fnction : ", ar)
    
print ("Before my_func : ", ar)
my_func()
print ("After my_func : ", ar)
結果
Before my_func :  [ 0.  0.  0.  0.]
in-fnction :  [ 0.  0.  0.  0.]
After my_func :  [ 0.  0.  0.  0.]

  • 若在function內re-assign並不會影響到global variable

ar = np.zeros(4)    
def my_func():
    ar = np.array([1,1,1,1])
    
print ("Before my_func : ", ar)
my_func()
print ("After my_func : ", ar)
結果
Before my_func :  [ 0.  0.  0.  0.]
After my_func :  [ 0.  0.  0.  0.]

  • 但是若加上global 宣告便可對array進行re-assign

ar = np.zeros(4)    
def my_func():
    global ar
    ar = np.array([1,1,1,1])
    
print ("Before my_func : ", ar)
my_func()
print ("After my_func : ", ar)
結果
Before my_func :  [ 0.  0.  0.  0.]
After my_func :  [1 1 1 1]

  • 若我們不對其做re-assign,而是更動其元素值,便可以更動到外部的array

ar = np.zeros(4)    
def my_func():
    ar[2] = 5
       
print ("Before my_func : ", ar)
my_func()
print ("After my_func : ", ar)
結果
Before my_func :  [ 0.  0.  0.  0.]
After my_func :  [ 0.  0.  5.  0.]
ar = np.zeros(4)    
def my_func():
    ar[:] = np.array([1,1,1,1])
       
print ("Before my_func : ", ar)
my_func()
print ("After my_func : ", ar)
結果
Before my_func :  [ 0.  0.  0.  0.]
After my_func :  [ 1.  1.  1.  1.]

◎ " - =  " vs  " - "

  • 根據上面的例子,我們知道re-assign只是創造一個新的引用對象,而不是更動引用

ar = np.zeros(4)    
def my_func(ar):
    ar = ar -1
       
print ("Before my_func : ", ar)
my_func(ar)
print ("After my_func : ", ar)
結果
Before my_func :  [ 0.  0.  0.  0.]
After my_func :  [ 0.  0.  0.  0.]

  • += 或者 -= 或者*= ...等等,為Augmented Assignment
  • 雖然可以達到類似 x = x + 1的效果,但是並不完全一樣 ,x = x + 1 使用__add__  methods。
  • 在可能的情況下,+= 使用 __iadd__ methods ,並不會創建新對象,再將其assign回目標,而是在performed in-place,因此會修改old object。

ar = np.zeros(4)    
def my_func(ar):
    ar -=1
       
print ("Before my_func : ", ar)
my_func(ar)
print ("After my_func : ", ar)
結果
Before my_func :  [ 0.  0.  0.  0.]
After my_func :  [-1. -1. -1. -1.] 

◎ 參考資料

6.3.1 Augmented Assignment statements
How do I pass a variable by reference?

留言