1、不錯的面試題網站
<a href="http://www.codingonway.com/">http://www.codingonway.com/</a>
<a href="https://github.com/revotu/python-interviews">https://github.com/revotu/python-interviews</a>
<a href="https://github.com/taizilongxu/interview_python">https://github.com/taizilongxu/interview_python</a>
2、Python是如何進行記憶體管理的?
Python GC主要使用引用計數(reference counting)來跟蹤和回收垃圾。在引用計數的基礎上,通過“标記-清除”(mark and sweep)解決容器對象可能産生的循環引用問題,通過“分代回收”(generation collection)以空間換時間的方法提高垃圾回收效率。
3、垃圾回收機制
當一個對象的引用計數歸零時,它将被垃圾收集機制處理掉。
當兩個對象a和b互相引用時,del語句可以減少a和b的引用計數,并銷毀用于引用底層對象的名稱。然而由于每個對象都包含一個對其他對象的應用,是以引用計數不會歸零,對象也不會銷毀。(進而導緻記憶體洩露)。為解決這一問題,解釋器會定期執行一個循環檢測器,搜尋不可通路對象的循環并删除它們。
4、引用計數機制
PyObject是每個對象必有的内容,其中ob_refcnt就是做為引用計數。當一個對象有新的引用時,它的ob_refcnt就會增加,當引用它的對象被删除、引用超出作用域或被重新指派,它的ob_refcnt就會減少.引用計數為0時,該對象生命就結束了。
優點:
1. 簡單
2. 實時性
缺點:
1. 維護引用計數消耗資源
2. 循環引用
5、标記-清除
基本思路是先按需配置設定,等到沒有空閑記憶體的時候從寄存器和程式棧上的引用出發,周遊以對象為節點、以引用為邊構成的圖,把所有可以通路到的對象打上标記,然後清掃一遍記憶體空間,把所有沒标記的對象釋放。
6、分代回收
分代回收的整體思想是:将系統中的所有記憶體塊根據其存活時間劃分為不同的集合,每個集合就成為一個“代”,垃圾收集頻率随着“代”的存活時間的增大而減小,存活時間通常利用經過幾次垃圾回收來度量。
Python預設定義了三代對象集合,索引數越大,對象存活時間越長。
舉例:
當某些記憶體塊M經過了3次垃圾收集的清洗之後還存活時,我們就将記憶體塊M劃到一個集合A中去,而新配置設定的記憶體都劃分到集合B中去。當垃圾收集開始工作時,大多數情況都隻對集合B進行垃圾回收,而對集合A進行垃圾回收要隔相當長一段時間後才進行,這就使得垃圾收集機制需要處理的記憶體少了,效率自然就提高了。在這個過程中,集合B中的某些記憶體塊由于存活時間長而會被轉移到集合A中,當然,集合A中實際上也存在一些垃圾,這些垃圾的回收會因為這種分代的機制而被延遲。
7、記憶體池機制
Python提供了對記憶體的垃圾收集機制,但是它将不用的記憶體放到記憶體池而不是傳回給作業系統。
Pymalloc機制。為了加速Python的執行效率,Python引入了一個記憶體池機制,用于管理對小塊記憶體的申請和釋放。
Python中所有小于256個位元組的對象都使用pymalloc實作的配置設定器,而大的對象則使用系統的malloc。
對于Python對象,如整數,浮點數和List,都有其獨立的私有記憶體池,對象間不共享他們的記憶體池。
8、函數參數
普通參數
即在調用函數時必須按照準确的順序來進行參數傳遞。
預設參數
即參數含有預設值,在調用函數時可以進行參數傳遞,若沒有進行參數傳遞則使用預設值,要注意,預設參數必須在普通參數的右側(否則解釋器無法解析)
元組參數,即 *args
參數格式化存儲在一個元組中,長度沒有限制,必須位于普通參數和預設參數之後
字典參數,即 **kwargs
參數格式化存儲在一個字典中,必須位于參數清單的最後面
9、Python裡面如何拷貝一個對象?(指派,淺拷貝,深拷貝的差別)
指派(=),就是建立了對象的一個新的引用,修改其中任意一個變量都會影響到另一個。
淺拷貝:建立一個新的對象,但它包含的是對原始對象中包含項的引用(如果用引用的方式修改其中一個對象,另外一個也會修改改變){1,完全切片方法;2,工廠函數,如list();3,copy子產品的copy()函數}
深拷貝:建立一個新的對象,并且遞歸的複制它所包含的對象(修改其中一個,另外一個不會改變){copy子產品的deep.deepcopy()函數}
copy 僅拷貝對象本身,而不拷貝對象中引用的其它對象。
deepcopy 除拷貝對象本身,而且拷貝對象中引用的其它對象。
10、Python中重載
函數重載主要是為了解決兩個問題:
1. 可變參數類型
2. 可變參數個數
解釋一:
那麼對于情況 1 ,函數功能相同,但是參數類型不同,python 如何處理?答案是根本不需要處理,因為 python 可以接受任何類型的參數,如果函數的功能相同,那麼不同的參數類型在 python 中很可能是相同的代碼,沒有必要做成兩個不同函數。
那麼對于情況 2 ,函數功能相同,但參數個數不同,python 如何處理?大家知道,答案就是預設參數。對那些缺少的參數設定為預設參數即可解決問題。因為你假設函數功能相同,那麼那些缺少的參數終歸是需要用的。
鑒于情況 1 跟 情況 2 都有了解決方案,python 自然就不需要函數重載了。
解釋二:
簡單來說,Python中為什麼不需要重載,重載要解決的是參數類型和參數個數的問題,對于類型,python不像是c語言整型要寫int,字元串要寫str,,,這些python都不需要。
那麼需要解決的就是傳遞參數個數問題,此時python可以傳遞清單呀,字典呀,可以使用*arg和**args呀,是以python根本不需要重載。
11、Python中單下劃線和雙下劃線
__foo__:一種約定,Python内部的名字,用來差別其他使用者自定義的命名,以防沖突.
_foo:一種約定,用來指定變量私有.程式員用來指定私有變量的一種方式.
__foo:這個有真正的意義:解析器用_classname__foo來代替這個名字,以差別和其他類相同的命名.
12、 __new__和__init__的差別
1. __new__是一個靜态方法,而__init__是一個執行個體方法.
2. __new__方法會傳回一個建立的執行個體,而__init__什麼都不傳回.
3. 隻有在__new__傳回一個cls的執行個體時,後面的__init__才能被調用.
4. 當建立一個新執行個體時調用__new__,初始化一個執行個體時用__init__.
13、單例模式
該模式的主要目的是確定某一個類隻有一個執行個體存在
使用子產品
其實,Python 的子產品就是天然的單例模式,因為子產品在第一次導入時,會生成 .pyc 檔案,當第二次導入時,就會直接加載 .pyc 檔案,而不會再次執行子產品代碼。是以,我們隻需把相關的函數和資料定義在一個子產品中,就可以獲得一個單例對象了。
将上面的代碼儲存在檔案 mysingleton.py 中,要使用時,直接在其他檔案中導入此檔案中的對象,這個對象即是單例模式的對象
使用類
基于__new__方法實作(推薦使用,友善)
當我們執行個體化一個對象時,是先執行了類的__new__方法(我們沒寫時,預設調用object.__new__),執行個體化對象;然後再執行類的__init__方法,對這個對象進行初始化,所有我們可以基于這個,實作單例模式
當我們實作單例時,為了保證線程安全需要在内部加入鎖,未加鎖部分并發執行,加鎖部分串行執行,速度降低,但是保證了資料安全
14、建立字典的方法
直接建立
dict = {'name':'earth', 'port':'80'}
工廠方法
items=[('name','earth'),('port','80')]
dict2=dict(items)
fromkeys()方法
dict1={}.fromkeys(('x','y'),-1)
dict={'x':-1,'y':-1}
dict2={}.fromkeys(('x','y'))
dict2={'x':None, 'y':None}
15、數組和元組之間的差別是什麼?
相同點
首先,清單與元組都是容器,是一系列的對象;
其次,二者都可以包含任意類型的元素甚至可以是一個序列。
不同點
清單和元組的“技術差異”是,清單是可變的,而元組是不可變的。
16、Python都有那些自帶的資料結構?
Python自帶的資料結構分為可變的和不可變的。
可變的有:
集合
字典
不可變的有:
字元串
元組
數字
數組
17、推導式
清單(list)推導式
功能:是提供一種友善的清單建立方法,是以,清單解析式傳回的是一個清單
例子:
>>> li=[i*2 for i in range(10) if i % 2 == 0]
>>> print li
[0, 4, 8, 12, 16]
清單解析式最擅長的方式就是對整個清單分别做相同的操作,并且傳回得到一個新的清單
字典(dict)推導式
集合(set)推導式
功能:集合推導式跟清單推導式差不多,都是對一個清單的元素全部執行相同的操作,但集合是一種無重複無序的序列
差別:跟清單推到式的差別在于:1.不使用中括号,使用大括号;2.結果中無重複;3.結果是一個set()集合,集合裡面是一個序列
>>> squared={i*2 for i in [1,1,2]}
>>> print squared
set([2, 4])
18、Python是如何進行類型轉換的?
Python提供了将變量或值從一種類型轉換成另一種類型的内置函數。比如int函數能夠将符合數學格式數字型字元串轉換成整數。否則,傳回錯誤資訊。
19、Python是如何被解釋的?
Python是一種解釋性語言,Python解釋器會将源代碼轉換成中間語言,之後再翻譯成機器碼再執行。
20、.Python中的負索引是什麼?
Python中的序列索引可以是正也可以是負。如果是正索引,0是序列中的第一個索引,1是第二個索引。如果是負索引,(-1)是最後一個索引而(-2)是倒數第二個索引。
21、Python的參數傳遞是值傳遞還是引用傳遞
1).Python的參數傳遞有:
位置參數
預設參數,
可變參數,
關鍵字參數
2).函數的傳值到底是值傳遞還是引用傳遞,要分情況
a.不可變參數用值傳遞:
像整數和字元串這樣的不可變對象,是通過拷貝進行傳遞的,因為你無論如何都不可能在原處改變不可變對象
b.可變參數是用引用傳遞的
比如像清單,字典這樣的對象是通過引用傳遞,和C語言裡面的用指針傳遞數組很相似,可變對象能在函數内部改變.
22、Xrange和range的差別是什麼?
xrange 函數說明:用法與range完全相同,所不同的是生成的不是一個數組,而是一個生成器。
>>> range(5)
[0, 1, 2, 3, 4]
>>> xrange(5)
xrange(5)
>>> list(xrange(5))
23、單引号,雙引号,三引号的差別
1),單引号和雙引号主要用來表示字元串
差別:
若你的字元串裡面本身包含單引号,必須用雙引号
比如:"can't find the log\n"
2).三引号
三單引号:'''python ''',也可以表示字元串一般用來輸入多行文本,或者用于大段的注釋
三雙引号:"""python""",一般用在類裡面,用來注釋類
24、類和執行個體
<a href="https://www.cnblogs.com/crazyrunning/p/6945183.html">https://www.cnblogs.com/crazyrunning/p/6945183.html</a>
25、類變量和執行個體變量
執行個體變量是對于每個執行個體都獨有的資料,而類變量是該類所有執行個體共享的屬性和方法。
class Dog:
kind = 'canine' # class variable shared by all instances
def __init__(self, name):
self.name = name # instance variable unique to each instance
類Dog中,類屬性kind為所有執行個體所共享;
執行個體屬性name為每個Dog的執行個體獨有。
26、類對象和執行個體對象
類對象
類對象僅支援兩個操作:
執行個體化;使用instance_name = class_name()的方式執行個體化,執行個體化操作建立該類的執行個體。
屬性引用;使用class_name.attr_name的方式引用類屬性。
執行個體對象
執行個體對象是類對象執行個體化的産物,執行個體對象僅支援一個操作:
屬性引用;與類對象屬性引用的方式相同,使用instance_name.attr_name的方式。
27、屬性綁定
我們說的屬性綁定,首先需要一個可變對象,才能執行綁定操作,使用objname.attr = attr_value的方式,為對象objname綁定屬性attr。
這分兩種情況:
若屬性attr已經存在,綁定操作會将屬性名指向新的對象;
若不存在,則為該對象添加新的屬性,後面就可以引用新增屬性。
類屬性綁定
類屬性的綁定發生在兩個地方:
類定義時;
運作時任意階段。
在類定義中,類屬性的綁定并沒有使用objname.attr = attr_value的方式,這是一個特例,其實是等同于後面使用類名綁定屬性的方式。
因為是動态語言,是以可以在運作時增加屬性,删除屬性。
執行個體屬性綁定
與類屬性綁定相同,執行個體屬性綁定也發生在兩個地方:
類執行個體有兩個特殊之處:
__init__在執行個體化時執行
Python執行個體調用方法時,會将執行個體對象作為第一個參數傳遞
是以,__init__方法中的self就是執行個體對象本身
28、屬性引用
類屬性引用
類屬性的引用,肯定是需要類對象的,屬性分為兩種:
資料屬性
函數屬性
執行個體屬性引用
使用執行個體對象引用屬性稍微複雜一些,因為執行個體對象可引用類屬性以及執行個體屬性。但是執行個體對象引用屬性時遵循以下規則:
總是先到執行個體對象中查找屬性,再到類屬性中查找屬性;
屬性綁定語句總是為執行個體對象建立新屬性,屬性存在時,更新屬性指向的對象。
29、Python 中的 is 和 ==
is is the identity comparison. #比較引用是否相同
== is the equality comparison. #比較内容是否相同
python中建立變量時,并不需要指定類型,因為每個變量實際上存儲的是一個引用,就是指向一個對象實體的指針。
is 判斷的就是這個指針的值是否相同,如果相同則表示兩個變量指向同一個對象實體。
而==則比較它們的内容是否相同
30、isinstance 和 type 的差別
class A:
pass
class B(A):
isinstance(A(), A) # returns True
type(A()) == A # returns True
isinstance(B(), A) # returns True
type(B()) == A # returns False
差別就是:
type()不會認為子類是一種父類類型。
isinstance()會認為子類是一種父類類型。
31、