一·Python是如何進(jìn)行內(nèi)存管理
Python是動態(tài)類型的語言燕差,對象與引用分離絮爷,在Python中,整數(shù)和短小的字符欢峰,Python都會緩存這些對象葬荷,以便重復(fù)使用。當(dāng)我們創(chuàng)建多個等于1的引用時纽帖,實際上是讓所有這些引用指向同一個對象宠漩。鏈接
關(guān)鍵字:引用計數(shù),垃圾回收懊直,標(biāo)記清除扒吁,內(nèi)存池分配機(jī)制
引用:
>>> a= 10
>>> b=10
>>> print id(a),id(b),id(10)
10414060 10414060 10414060
>>>
>>> import sys
>>> print sys.getrefcount(a),sys.getrefcount(b),sys.getrefcount(10)
160 160 160
>>> c = b
>>> print sys.getrefcount(c)
159
>>> print sys.getrefcount(a)
159
>>> d= c
>>> print sys.getrefcount(d)
160
引用環(huán):
兩個對象可能相互引用,從而構(gòu)成所謂的引用環(huán)
即使是一個對象室囊,只需要自己引用自己雕崩,也能構(gòu)成引用環(huán)
>>> g = [ ]
>>> g.append(g)
>>> print sys.getrefcount(g)
3
引用減少:通過del 來減少引用 ......
垃圾回收:引用計數(shù)為0.
分代回收:存活時間越久的對象,越不可能在后面的程序中變成垃圾融撞,所以減少在垃圾回收中掃描它們的頻率盼铁。
孤立的引用環(huán):標(biāo)記-清除
內(nèi)存池機(jī)制:多層封裝管理,大內(nèi)存malloc尝偎,小內(nèi)存pymalloc饶火,python對象(list,整數(shù),浮點(diǎn)數(shù))都有其獨(dú)立的內(nèi)存池.
內(nèi)存池:
- Python 的內(nèi)存機(jī)制呈現(xiàn)金字塔形狀鹏控,-1,-2 層主要有操作系統(tǒng)進(jìn)行操作肤寝;
- 第 0 層是 C 中的 malloc当辐,free 等內(nèi)存分配和釋放函數(shù)進(jìn)行操作;
- 第 1 層和第 2 層是內(nèi)存池鲤看,有 Python 的接口函數(shù) PyMem_Malloc 函數(shù)實現(xiàn)缘揪,當(dāng)對象小于256K 時有該層直接分配內(nèi)存;
- 第 3 層是最上層刨摩,也就是我們對 Python 對象的直接操作寺晌;
Python 在運(yùn)行期間會大量地執(zhí)行 malloc 和 free 的操作,頻繁地在用戶態(tài)和核心態(tài)之間進(jìn)行切換澡刹,這將嚴(yán)重影響 Python 的執(zhí)行效率呻征。為了加速 Python 的執(zhí)行效率,Python 引入了一個內(nèi)存池機(jī)制罢浇,用于管理對小塊內(nèi)存的申請和釋放陆赋。Python 內(nèi)部默認(rèn)的小塊內(nèi)存與大塊內(nèi)存的分界點(diǎn)定在 256 個字節(jié),當(dāng)申請的內(nèi)存小于 256 字節(jié)時嚷闭,PyObject_Malloc 會在內(nèi)存池中申請內(nèi)存攒岛;當(dāng)申請的內(nèi)存大于 256 字節(jié)時,PyObject_Malloc 的行為將蛻化為 malloc 的行為胞锰。當(dāng)然灾锯,通過修改 Python 源代碼,我們可以改變這個默認(rèn)值嗅榕,從而改變 Python 的默認(rèn)內(nèi)存管理行為顺饮。
調(diào)優(yōu)手段(了解)
1.手動垃圾回收
2.調(diào)高垃圾回收閾值
3.避免循環(huán)引用(手動解循環(huán)引用和使用弱引用)
二·Python 引用/賦值,淺拷貝凌那,深拷貝
賦值/引用:創(chuàng)建了對象的一個新的引用兼雄,修改其中任意一個變量都會影響到另一個。
淺拷貝:創(chuàng)建一個新的對象帽蝶,但它包含的是對原始對象中包含項的引用(如果用引用的方式修改其中一個對象赦肋,另外一個也會修改改變){1,完全切片方法:a=b[::];2励稳,工廠函數(shù)佃乘,如list();3驹尼,copy模塊的copy()函數(shù)}
深拷貝:創(chuàng)建一個新的對象趣避,并且遞歸的復(fù)制它所包含的對象(修改其中一個,另外一個不會改變){copy模塊的deep.deepcopy()函數(shù)}
拷貝操作的警告 :
1扶欣、對于非容器類型鹅巍,如數(shù)字,字符料祠,以及其它“原子”類型骆捧,沒有拷貝一說。產(chǎn)生的都是原對象的引用髓绽。
2敛苇、如果元組變量值包含原子類型對象,即使采用了深拷貝顺呕,也只能得到淺拷貝
三·Python 單引號枫攀,雙引號,三引號的區(qū)別
單引號和雙引號是等效的株茶,如果要換行来涨,需要符號(),三引號則可以直接換行,并且可以包含注釋启盛。
單引號:s4 = ‘Let\’s go’
雙引號:s5 = “Let’s go”
s6 = ‘I realy like“python”!’
四·Python 去重蹦掐,排序,re模塊僵闯,lambda卧抗,tuple和list的轉(zhuǎn)換
去重:set()
排序:sorted(),list.sort()
re match與search區(qū)別
lambda:匿名函數(shù),需要一個函數(shù)鳖粟,但是又不想費(fèi)神去命名一個函數(shù)社裆,a=lambdax,y:x+y
轉(zhuǎn)換:tuple(),list()
四·Python try ... except
try下的語句正常執(zhí)行,則執(zhí)行else塊代碼向图。如果發(fā)生異常泳秀,就不會執(zhí)行。
在except中return后還會執(zhí)行finally中的代碼张漂,如果存在finally語句晶默,最后總是會執(zhí)行。用 raise 方法可以拋出自定義異常航攒。
except: #捕獲所有異常
except: <異常名>: #捕獲指定異常
except:<異常名 1, 異常名 2> : 捕獲異常 1 或者異常 2
except:<異常名>,<數(shù)據(jù)>:捕獲指定異常及其附加的數(shù)據(jù)
except:<異常名 1,異常名 2>:<數(shù)據(jù)>:捕獲異常名 1 或者異常名 2,及附加的數(shù)據(jù)
五·貪婪匹配與非貪婪匹配
String str="abcaxc";
貪婪匹配:最大長度匹配磺陡,例如去匹配str:abcaxc(ab*c)。
非貪婪匹配:就是匹配到結(jié)果就好漠畜,就少的匹配字符币他。例如:abc(ab*c)。
六·Python的可變與不可變數(shù)據(jù)類型
可變數(shù)據(jù)類型:列表list和字典dict憔狞;不可變數(shù)據(jù)類型:整型int蝴悉、浮點(diǎn)型float、字符串型string和元組tuple瘾敢。
不可變數(shù)據(jù)類型拍冠,不允許變量的值發(fā)生變化尿这,如果改變了變量的值,相當(dāng)于是新建了一個對象庆杜,而對于相同的值的對象射众,在內(nèi)存中則只有一個對象,內(nèi)部會有一個引用計數(shù)來記錄有多少個變量引用這個對象晃财;
可變數(shù)據(jù)類型叨橱,允許變量的值發(fā)生變化,即如果對變量進(jìn)行append断盛、+=等這種操作后罗洗,只是改變了變量的值,而不會新建一個對象钢猛,變量引用的對象的地址也不會變化伙菜,不過對于相同的值的不同對象,在內(nèi)存中則會存在不同的對象命迈,即每個對象都有自己的地址仇让,相當(dāng)于內(nèi)存中對于同值的對象保存了多份,這里不存在引用計數(shù)躺翻,是實實在在的對象丧叽。
操作不可變對象:
>>> a =(2,3)
>>> print a[1]
3
>>> a[1] =3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
七·print 調(diào)用 Python 中底層的什么方法
print 方法默認(rèn)調(diào)用 sys.stdout.write 方法,即往控制臺打印字符串公你。
八· input()函數(shù)
在 Python3 中踊淳,input()獲取用戶輸入,不論用戶輸入的是什么陕靠,獲取到的都是字符串類型的迂尝。
在 Python2 中有 raw_input()和 input():
raw_input()和 Python3 中的 input()作用是一樣的,
input()輸入的是什么數(shù)據(jù)類型的剪芥,獲取到的就是什么數(shù)據(jù)類型的垄开。
九· range 和 xrange 的區(qū)別
兩者用法相同,不同的是 range 返回的結(jié)果是一個列表税肪,而 xrange 的結(jié)果是一個生成器溉躲,前者是直接開辟一塊內(nèi)存空間來保存列表,后者是邊循環(huán)邊使用益兄,只有使用時才會開辟內(nèi)存空間锻梳,所以當(dāng)列表很長時,使用 xrange 性能要比 range 好净捅。
十· read疑枯、readline 和 readlines 的區(qū)別
read:讀取整個文件。
readline:讀取下一行蛔六,使用生成器方法荆永。
readlines:讀取整個文件到一個迭代器以供我們遍歷废亭。
十一·init 和new的區(qū)別
init 通常用于初始化一個新實例,控制這個初始化的過程具钥,比如添加一些屬性滔以, 做一些額外的操作,發(fā)生在類實例被創(chuàng)建完以后氓拼。它是實例級別的方法。
new 通常用于控制生成一個新實例的過程抵碟。它是類級別的方法桃漾。
相關(guān)鏈接
十二·模塊和包
在 Python 中,模塊是搭建程序的一種方式拟逮。每一個 Python 代碼文件都是一個模塊撬统,并可以引用
其他的模塊,比如對象和屬性敦迄。
一個包含許多 Python 代碼的文件夾是一個包恋追。一個包可以包含模塊和子文件夾。
十三·Python 特性
Python 是強(qiáng)類型的動態(tài)腳本語言:
強(qiáng)類型:不允許不同類型相加罚屋。
動態(tài):不使用顯示數(shù)據(jù)類型聲明苦囱,且確定一個變量的類型是在第一次給它賦值的時候。
腳本語言:一般也是解釋型語言脾猛,運(yùn)行代碼只需要一個解釋器撕彤,不需要編譯。
類型轉(zhuǎn)換:int(‘str’猛拴,base=’n’)
>>> int('0x004f',base=16)
79
解釋性語言和編譯性語言:
解釋性語言在運(yùn)行程序的時候才會進(jìn)行翻譯羹铅。
編譯型語言寫的程序在執(zhí)行之前,需要一個專門的編譯過程愉昆,把程序編譯成機(jī)器語言(可執(zhí)行文件)
十四·Python 程序運(yùn)行提升性能
1职员、使用多進(jìn)程,充分利用機(jī)器的多核性能
2跛溉、對于性能影響較大的部分代碼焊切,可以使用 C 或 C++編寫
3、對于 IO 阻塞造成的性能影響芳室,可以使用 IO 多路復(fù)用來解決(同一個線程內(nèi)同時處理多個IO請求的目的)
4蛛蒙、盡量使用 Python 的內(nèi)建函數(shù)
5、盡量使用局部變量
十五·Python 自省
自帶說明的名字叫自省渤愁。(反射是 java 的說法牵祟,Python叫自省)
自省簡單的說,就是用 python 的代碼自己告訴這個對象是什么抖格,有什么诺苹,以及祖宗是什么咕晋,子孫是什么....
python 提供的自省機(jī)制:help,dir 收奔。其他的可以用 這兩個找到
十六·Python 代碼規(guī)范(PEP8規(guī)范)
- 變量
常量:大寫加下劃線 USER_CONSTANT
私有變量 : 小寫和一個前導(dǎo)下劃線 _private_value(Python 中不存在私有變量掌呜,這只是程序員之間的一個約定,用于警告說明這是一個私有變量坪哄,外部類不要去訪問它质蕉。但實際上,外部類還是可以訪問到這個變量)
內(nèi)置變量 : 小寫翩肌,兩個前導(dǎo)下劃線和兩個后置下劃線 class(前導(dǎo)下劃線會導(dǎo)致變量在解釋期間被更名模暗。這是為了避免內(nèi)置變量和其他變量產(chǎn)生沖突。用戶定義的變量要嚴(yán)格避免這種風(fēng)格)
- 函數(shù)和方法
總體:小寫和下劃線念祭。
私有方法 :小寫和一個前導(dǎo)下劃線
特殊方法 :小寫和兩個前導(dǎo)下劃線兑宇,兩個后置下劃線
這種風(fēng)格只應(yīng)用于特殊函數(shù),比如操作符重載等粱坤。
函數(shù)參數(shù) : 小寫和下劃線隶糕,缺省值等號兩邊無空格
類
類總是使用駝峰格式命名,所有單詞首字母大寫其余字母小寫站玄。類名應(yīng)該簡明枚驻,精確,并足以從中理解類所完成的工作株旷。常見的一個方法是使用表示其類型或者特性的后綴模塊和包
除特殊模塊 init 之外测秸,模塊名稱都使用不帶下劃線的小寫字母。參數(shù)
不要用斷言來實現(xiàn)靜態(tài)類型檢測灾常。
不要濫用 *args 和 **kwargs霎冯。其他
1.使用 has 或 is 前綴命名布爾元素
is_connect = True
2.驗證腳本
可以安裝一個 pep8 腳本用于驗證你的代碼風(fēng)格是否符合 PEP8
1-5:原文鏈接
6-15:《黑馬程序員》