is 和 ==什么區(qū)別?
在Python中 is 是用來判斷兩個對象的內(nèi)存地址是否一樣,而 == 號是判斷兩個對象(a he b)中的內(nèi)容是否一樣。也就是說is是用來比較房間的門牌號,而==是用來比較房間中的內(nèi)容
先看下面的內(nèi)存示意圖和一些代碼運(yùn)行的圖



總結(jié)
? 小整數(shù)[-5,257)共用對象,常駐內(nèi)存
? 單個字符共用對象,常駐內(nèi)存
? 單個單詞,不可修改,默認(rèn)開啟intern機(jī)制,共用對象,引用計數(shù)為0,則銷毀
? 字符串(含有空格),不可修改,沒開啟intern機(jī)制,不共用對象,引用計數(shù)為0,銷毀
? 大整數(shù)不共用內(nèi)存,引用計數(shù)為0,銷毀
數(shù)值類型和字符串類型在 Python 中都是不可變的,這意味著你無法修改這個對象的值,每次對變量的修改,實際上是創(chuàng)建一個新的對象
copy模塊
import copy
a1=[1,2,3,4]
a2=copy.copy(a1)
a1= a2
True
a1 is a2
False
這個是淺拷貝會拷貝對象最上面的一層這里可以看到 a1和a2的門牌號是不一樣的,淺拷貝是有弊端的,也就是只會拷貝頂層而對象中的深層是無法拷貝的,比如 列表對象里套了一個或者多個列表對象
import copy
a1=[1,2,3,4]
a2=[1,3,5,a1]
a3=copy.copy(a2)
a2[3][0]=12
a2
[1,3,5,[12,2,3,4]]
a3
[1,3,5,[12,2,3,4]]
從上面的例子可以看出淺拷貝是藕斷絲連的并不能解決深層對象的拷貝問題,這里就要用到深拷貝(deepcopy)
import copy
a1=[1,2,3,4]
a2=[1,3,5,a1]
a3=copy.deepcopy(a2)
a2[3][0]=12
a2
[1,3,5,[12,2,3,4]]
a3
[1,3,5,[1,2,3,4]]
問題完美解決,當(dāng)然有人問既然有了深拷貝為什么還要有淺拷貝,有錢(淺)嘛大家都喜歡,所以就追加了一個淺拷貝的方法,當(dāng)然這是開玩笑的,因為深拷貝是遞歸拷貝在忽略對象套對象的情況下,對大量數(shù)據(jù)拷貝時速度很慢,效率低遞歸的通病。
python 的垃圾回收(gc)機(jī)制(Garbage collection)(選修,純理論)
python采用了和C#、Java一樣的手段,專業(yè)的垃圾回收機(jī)制,而不是c和c++ 用戶自己管理內(nèi)存的方式,關(guān)于自由管理大家可以百度一下。
python采用的垃圾回收機(jī)制是引用計數(shù)為主,標(biāo)記-清除和分代收集為輔。
Python中的所有都是,他們的核心是一個結(jié)構(gòu)體:PyObject
也就是每一個對象都有PyObject這個結(jié)構(gòu)體
//我的python版本是cpython
typedef struct_object {
int ob_refcnt;
struct_typeobject *ob_type;
} PyObject;
其中PyObject就是每個對象的引用計數(shù)。
在創(chuàng)建一個對象的時候PyObject就會生成一個非零的自然數(shù)
Python 3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:54:40) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> def test():
... pass
...
>>> d= test
>>> del test
>>> d
<function test at 0x000001B821C1AF28>
>>> test()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'test' is not defined
>>>
從上面的代碼可以看出d =test 創(chuàng)建了一個新的對象,在原有的對象的PyObject加一 ,
在刪除這個對象的時候 PyObject減一
而且這兩個對象共用一個 PyObject
>>> a= 110
>>> sys.getrefcount(a)
3
>>> b = a
>>> sys.getrefcount(a)
4
>>> sys.getrefcount(b)
4
>>> del b
>>> sys.getrefcount(a)
3
>>> b =a
>>> sys.getrefcount(a)
4
>>> sys.getrefcount(b)
4
>>> del a
>>> sys.getrefcount(b)
3
>>> b
110
>>> a = 300
>>> sys.getrefcount(a)
2
>>> b =a
>>> sys.getrefcount(b)
3
>>> sys.getrefcount(a)
3
>>> del a
>>> sys.getrefcount(b)
2
>>> sys.getrefcount(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>>
大整數(shù)池和小整數(shù)池我都做了測試。
當(dāng)del 的時候 就會PyObject置零,此時gc就會回收這塊內(nèi)存。
引用的計數(shù)的優(yōu)點就是:
??? 簡單
??? 實時性:一旦沒有引用,內(nèi)存就直接釋放了。不用像其他機(jī)制等到特定時 ??機(jī)。實時性還帶來一個好處:處理回收內(nèi)存的時間分?jǐn)偟搅似綍r。
引用的計數(shù)的缺點就是:
??? 維護(hù)引用計數(shù)耗費資源
??? 循環(huán)引用
list1 = []
list2 = []
list1.append(list2)
list2.append(list1)
如果對于第一個還能忍受,那么循環(huán)引用就是致命的。循環(huán)引用導(dǎo)致內(nèi)存泄露,注定python還將引入新的回收機(jī)制。(標(biāo)記清除和分代收集)
文章的就寫到這里......關(guān)于標(biāo)記清除,分代我的理解也不是太深,也不在這里誤人子弟。
晚安!