1、對象
對于python來說一切皆對象,所有的變量都是內(nèi)存中一個對象的“引用”。
類型是屬于對象的,而不是變量的。而對象根據(jù)是否可變分為:
1、可變對象。例如list、dict、set
2、不可變對象。例如string、touple、numbers
而不可變對象中,有一部分當我們使用id()去查看他的內(nèi)存地址,會發(fā)現(xiàn),內(nèi)存地址是相同的,另一部分卻不相同。
#小的int類型相同
a=1
b=1
id(a)
Out[125]: 1529015408
id(b)
Out[126]: 1529015408
#大的int類型不相同
a=11111111111
b=11111111111
id(a)
Out[129]: 96958192
id(b)
Out[130]: 96958320
#tuple類型不相同
a=(1,2)
b=(1,2)
id(a)
Out[133]: 88059016
id(b)
Out[134]: 96127432
#str相同
a='absdf'
b='absdf'
id(a)
Out[137]: 96999888
id(b)
Out[138]: 96999888
這個是什么原因呢,假如說從節(jié)約內(nèi)存角度來說的話,那么所有的不可變對象不應該都復用、相同嗎?
Python里一切都是對象。所以1,2,3,4...這些整數(shù)也都是對象。這些基本的不可變對象在python里會被頻繁的引用、創(chuàng)建,如果不找到好的辦法的話,很容易讓python引發(fā)效率瓶頸,所以python引入了整數(shù)對象池的機制。
- int中[-5, 256] 這些小整數(shù)被定義在了這個對象池里.所以當引用小整數(shù)時會自動引用整數(shù)對象池里的對象的.
- string對象也是不可變對象,python有個intern機制,簡單說就是維護一個字典,這個字典維護已經(jīng)創(chuàng)建字符串(key)和它的字符串對象的地址(value),每次創(chuàng)建字符串對象都會和這個字典比較,沒有就創(chuàng)建,重復了就用指針進行引用就可以了。
- float類型可以認為每個賦值都是創(chuàng)建一個對象,因為float有點多,所以沒必要和int一樣了。
- tuple它是不可變對象,理應和int和string一樣會做一個緩存,但是書上沒有說明,于是看了看源碼,發(fā)現(xiàn)tuple的數(shù)據(jù)結構很簡單,簡單到不能再簡單,就是一個數(shù)組,里面是元組的迭代對象,這個對象指向的是各個元素.最關鍵的是元組沒有實現(xiàn)intern機制!所以元組雖然是不可變對象,但它同時也是一個數(shù)組,這個數(shù)組和c里的數(shù)組一樣,每次創(chuàng)建都會分配內(nèi)存空間。
2、參數(shù)傳遞
當一個函數(shù)變量A==>指向內(nèi)存地址1529015440,作為參數(shù)被傳給一個函數(shù)func()時,函數(shù)func()會把這個變量A的對于對象的"引用"復制一份為變量B==>指向1529015440,放入函數(shù)中使用。
而在函數(shù)中進行修改這個變量對象B時,與外部的對象A沒有任何關系。但是當內(nèi)存地址1529015440為可變對象時,修改了對象B就會修改掉這個內(nèi)存地址對象,從而修改掉A;如果內(nèi)存地址1529015440為不可變對象時,修改對象B就會將B指向內(nèi)存地址1529015440更改為新的內(nèi)存地址比如1529015444,此時A依然指向內(nèi)存地址1529015440,A不會發(fā)生變化。
A = 1
B = [1,2]
def func(key):
print(id(key))
if isinstance(key, list):
key[0]=2
else:
key=2
print(id(key))
id(A)
Out[9]: 1529015408
func(A)
1529015408
1529015440
id(B)
Out[12]: 96144136
func(B)
96144136
96144136
參考1:https://www.stackoverflow.com
參考2:http://www.itdecent.cn