python的可變對象和不可變對象

python調(diào)用的函數(shù),傳遞參數(shù)的時候,是傳值還是傳遞引用?

image.png

對于一段這樣的代碼,在main函數(shù)里面創(chuàng)建一個對象val=3,然后在test_function 里面把它修改成300,然后在main函數(shù)里面輸出,它的值應該是3還是300?

答案:3 , val沒有被修改。

如果從這個角度去看,那么我們可以認為python函數(shù)參數(shù)傳遞的是值,而不是引用嗎?答:不可以,看下面一個例子


image.png

main函數(shù)里面一個為空的list,在函數(shù)里面去修改它,如果是值傳遞,那么調(diào)用函數(shù)之后,val應該不變。如果是引用傳遞,那么val被修改,里面有一個“hello”。去運行程序,輸出的結(jié)果是“hello”(val已經(jīng)被修改)

so,問題就來了,為什么有的參數(shù)傳遞進入,就可以被修改,為什么有的參數(shù)傳遞進入,就不會被修改?

在《編寫高質(zhì)量的代碼——改成python程序的n個建議》書中,作者解釋了這個問題。

image.png

意思是,python的函數(shù)參數(shù)傳遞,既不是值傳遞,也不是引用傳遞。它的傳遞方式是”傳對象“。函數(shù)參數(shù)在傳遞的過程中,將整個對象傳入。

1.對可變對象的修改在函數(shù)外部以及內(nèi)部都可見;
2.對于不可變對象,由于不能真正的修改,往往是創(chuàng)建一個新的對象,然后通過賦值來實現(xiàn)。,所以,外部是不可見的。

這也就解釋了,為什么如果val是一個數(shù)字的時候,函數(shù)內(nèi)部對val修改,外部并不可見。如果val是一個list,那么對val修改,那么外部是可見的。

so,問題又來了,什么是可變對象,什么是不可變對象?

python不可變對象:int,string,float,tuple
python可變對象:dict,list

當修改一個不可變對象的時候:


image.png

有i和j倆個變量的值為77,通過打印77的ID和變量i,j在內(nèi)存中的id我們得知它們都是指向同一塊內(nèi)存。所以說i和j都是指向同一個對象的。然后我們修改j的值,讓j的值+1.按道理j修改之后應該i的值也發(fā)生改變的,因為它們都是指向的同一塊內(nèi)存,但結(jié)果是并沒有。因為int類型是不可變類型,所有其實是j復制了一份到新的內(nèi)存地址然后+1,然后j又指向了新的地址。所以j的內(nèi)存id發(fā)生了變化。

image.png

so,小結(jié)一下,修改一個不可變對象的時候,會創(chuàng)建一個新的對象,然后指過去。所以,id會改變。

對于一個可變對象,傳遞參數(shù)的時候,對它的修改是不會改id的。


def test_function(val):
    print (id(val))
    val=300
    print (id(val))
    

def test_function2(val):
    val.append('hello')
    print (id(val))


if __name__=="__main__":
    """
    val=[]
    print (id(val))
    test_function2(val)
    """
    val=3
    print (id(val))
    test_function(val)

小結(jié)一下:

  1. python函數(shù)傳遞參數(shù)傳遞的是對象
  2. 對象分為可變對象和不可變對象,如果修改一個不可變對象的時候,會創(chuàng)建一個新的對象。如果修改一個可變對象,那么就在原來的對象上的修改。

給一個例子,分析一下:(《編寫高質(zhì)量的代碼》書上面的例子)


image.png

下一個問題,對象的拷貝,什么是深拷貝or淺拷貝?

前幾次寫程序幾個小bug都是由于對 對象的賦值,淺拷貝,深拷貝的概念沒有搞透徹。

  1. 賦值


    image.png

創(chuàng)建一個叫will的list,然后讓will賦值給wilber。然后,看一下這兩個id,是完全相同的。

然后,看一下list里面的元素的id是不是相同。


image.png

答案也是完全相同的。

我們試著修改一下list里面的東西:

will[0] = "Wilber"
will[2].append("CSS")

修改之后,發(fā)現(xiàn)will[0]的id改變了,但是will[2]的id沒有變。
因為will[0]是一個不可變的對象,所以修改之后id就可變。will[2]是一個可變對象,修改之后id不變。

#給個例子  可以跑一下 看看
will = ["Will", 28, ["Python", "C#", "JavaScript"]]
wilber = will
print (id(will))
print (will)
print ([id(ele) for ele in will])
print (id(wilber))
print (wilber)
print ([id(ele) for ele in wilber])

print ("***update*****")
will[0] = "Wilber"
will[2].append("CSS")
print (id(will))
print (will)
print ([id(ele) for ele in will])
print (id(wilber))
print (wilber)
print ([id(ele) for ele in wilber])

結(jié)果:


image.png
image.png
  1. 淺拷貝
    注意,切片也是淺拷貝。
import copy

will = ["Will", 28, ["Python", "C#", "JavaScript"]]
wilber = copy.copy(will)

print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]

will[0] = "Wilber"
will[2].append("CSS")
print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]
image.png
  1. 深拷貝
import copy

will = ["Will", 28, ["Python", "C#", "JavaScript"]]
wilber = copy.deepcopy(will)

print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]

will[0] = "Wilber"
will[2].append("CSS")
print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]
image.png

參考:

  1. 《編寫高質(zhì)量的代碼》
  2. 可變對象and不可變對象 : http://www.itdecent.cn/p/c5582e23b26c
  3. 深拷貝and淺拷貝 :
    http://www.cnblogs.com/wilber2013/p/4645353.html
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內(nèi)部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,823評論 18 399
  • //Clojure入門教程: Clojure – Functional Programming for the J...
    葡萄喃喃囈語閱讀 4,068評論 0 7
  • Python在heap中分配的對象分為兩類:可變對象和不可變對象。 可變對象:list,dict 不可變對象:in...
    XF_天閱讀 803評論 0 2
  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,653評論 30 472
  • 出差,喜歡做火車,尤其慢車,記得上學時常做的綠皮車,常常沒座位,一搖就是十個小時,但很享受,看著不斷錯過的...
    cmBook閱讀 626評論 0 48

友情鏈接更多精彩內(nèi)容