close
曾經學過C++的,回頭過來看Python,可能就會誤認為Python 也有pass-by-value, pass by reference的概念就怕會不會因此在參數傳遞時產生大量不必要的運算量而拖慢了系統效能
但其實Python主要背後運作都是基於pass by reference的作法去實現的,其背後意涵有兩個
1. Python 都是傳遞物件的參照,但是傳過去說穿了也只是複製參照的數值,如實的傳進method當中,並且這個數值同樣指向相同的物件
2. 有些資料型態是可變的(mutable),反之有些則是不可變的(immutable)
也就是說:
如果你傳送一個可變得物件給一個method,則這兩個method會得到相同的reference指到相同的地方去,這時候你就可以隨心所欲的使用、修改更動它並且任何的修改都會一並反映到method外頭去
但是如果你在method當中rebind他的話,則在method以外則會維持原本指向的物件,所以在method裡面的變化自然就不會影響到外頭。
如果你傳遞一個不可變的物件給method的話,則不管在哪邊,一旦指定了就再也無法修改物件的數值了
唯一能做的就是rebind它,但是如上一點所說的一樣,經rebind後則無論內部怎麼作手腳,都不會影響到外頭的!!
直接來看個例子吧
- List - a mutable type 可變的型態
def try_to_change_list_contents(the_list): print('got', the_list) the_list.append('four') print('changed to', the_list) outer_list = ['one', 'two', 'three'] print('before, outer_list =', outer_list) try_to_change_list_contents(outer_list) print('after, outer_list =', outer_list)
輸出:
before, outer_list = ['one', 'two', 'three'] got ['one', 'two', 'three'] set to ['one', 'two', 'three', 'four'] after, outer_list = ['one', 'two', 'three', 'four']
因為the_list的參數是以傳值的方式拿到的,所以在method內部直接重新賦予一個新的list並不會影響到外部scope,在內部的the_list其實就只是out_list的參照副本,所以我們將the_list重新指向另外一個list,很顯然的,這樣的改動完全不會影響到out_list所指向的list。
2. String - an immutable type
字串型態是Immutable的,所以我們無法對任何定義後的字串繼續更動它,唯一能做的就是改變參照對向
def try_to_change_string_reference(the_string): print('got', the_string) the_string = 'In a kingdom by the sea' print('set to', the_string) outer_string = 'It was many and many a year ago' print('before, outer_string =', outer_string) try_to_change_string_reference(outer_string)print('after, outer_string =', outer_string)
輸出:
before, outer_string = It was many and many a year ago got It was many and many a year ago set to In a kingdom by the sea after, outer_string = It was many and many a year ago
同樣的,因為the_string 參數是以傳值的方式傳入,傳入物件的參照,所以當我們指定新的字串於method裡面,則於method以外的地方,都不會受到任何影響,因為the_string只是out_string的參照複製品,當我們重新指定the_string新的字串的時候,理所當然的完全不會影響到out_string。
其實背後的道理就跟C++的pass "by reference",其實也是pass by value,但是這裡的value其實是所謂的物件位址。
ref :
文章標籤
全站熱搜
留言列表