天天看點

【Python面試題】【基礎篇】持續更新中...

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)推導式

功能:是提供一種友善的清單建立方法,是以,清單解析式傳回的是一個清單

例子:

&gt;&gt;&gt; li=[i*2 for i in range(10) if i % 2 == 0]

&gt;&gt;&gt; print li

[0, 4, 8, 12, 16]

清單解析式最擅長的方式就是對整個清單分别做相同的操作,并且傳回得到一個新的清單

字典(dict)推導式

集合(set)推導式

功能:集合推導式跟清單推導式差不多,都是對一個清單的元素全部執行相同的操作,但集合是一種無重複無序的序列

差別:跟清單推到式的差別在于:1.不使用中括号,使用大括号;2.結果中無重複;3.結果是一個set()集合,集合裡面是一個序列

&gt;&gt;&gt; squared={i*2 for i in [1,1,2]}

&gt;&gt;&gt; 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完全相同,所不同的是生成的不是一個數組,而是一個生成器。

&gt;&gt;&gt; range(5)

[0, 1, 2, 3, 4]

&gt;&gt;&gt; xrange(5)

xrange(5)

&gt;&gt;&gt; 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、