python面試題(1)

python簡單面試題

1.Python是如何進行內存管理的?

答:從三個方面來說,一對象的引用計數機制,二垃圾回收機制,三內存池機制

一、對象的引用計數機制

Python內部使用引用計數,來保持追蹤內存中的對象,所有對象都有引用計數。

引用計數增加的情況:

1,一個對象分配一個新名稱

2,將其放入一個容器中(如列表、元組或字典)

引用計數減少的情況:

1,使用del語句對對象別名顯示的銷燬

2,引用超出作用域或被重新賦值

sys.getrefcount( )函數可以獲得對象的當前引用計數

多數情況下,引用計數比你猜測得要大得多。對於不可變數據(如數字和字符串),解釋器會在程序的不同部分共享內存,以便節約內存。

二、垃圾回收

1,當一個對象的引用計數歸零時,它將被垃圾收集機制處理掉。

2,當兩個對象a和b相互引用時,del語句可以減少a和b的引用計數,並銷燬用於引用底層對象的名稱。然而由於每個對象都包含一個對其他對象的應用,因此引用計數不會歸零,對象也不會銷燬。(從而導致內存泄露)。爲解決這一問題,解釋器會定期執行一個循環檢測器,搜索不可訪問對象的循環並刪除它們。

三、內存池機制

Python提供了對內存的垃圾收集機制,但是它將不用的內存放到內存池而不是返回給操作系統。

1,Pymalloc機制。爲了加速Python的執行效率,Python引入了一個內存池機制,用於管理對小塊內存的申請和釋放。

2,Python中所有小於256個字節的對象都使用pymalloc實現的分配器,而大的對象則使用系統的malloc。

3,對於Python對象,如整數,浮點數和List,都有其獨立的私有內存池,對象間不共享他們的內存池。也就是說如果你分配又釋放了大量的整數,用於緩存這些整數的內存就不能再分配給浮點數。

2.什麼是lambda函數?它有什麼好處?

答:lambda 表達式,通常是在需要一個函數,但是又不想費神去命名一個函數的場合下使用,也就是指匿名函數

lambda函數:首要用途是指點短小的回調函數

lambda [arguments]:expression
>>> a=lambdax,y:x+y
>>> a(3,11)

3.Python裏面如何實現tuple和list的轉換?

答:直接使用tuple和list函數就行了,type()可以判斷對象的類型

4.請寫出一段Python代碼實現刪除一個list裏面的重複元素

答:

1,使用set函數,set(list)

2,使用字典函數,

>>>a=[1,2,4,2,4,5,6,5,7,8,9,0]
>>> b={}
>>>b=b.fromkeys(a)
>>>c=list(b.keys())
>>> c

5.編程用sort進行排序,然後從最後一個元素開始判斷

a=[1,2,4,2,4,5,7,10,5,5,7,8,9,0,3]
a.sort()
last=a[-1]
for i inrange(len(a)-2,-1,-1):
if last==a[i]:
del a[i]
else:last=a[i]
print(a)

6.Python裏面如何拷貝一個對象?(賦值,淺拷貝,深拷貝的區別)

答:賦值(=),就是創建了對象的一個新的引用,修改其中任意一個變量都會影響到另一個。

淺拷貝:創建一個新的對象,但它包含的是對原始對象中包含項的引用(如果用引用的方式修改其中一個對象,另外一個也會修改改變){1,完全切片方法;2,工廠函數,如list();3,copy模塊的copy()函數}

深拷貝:創建一個新的對象,並且遞歸的複製它所包含的對象(修改其中一個,另外一個不會改變){copy模塊的deep.deepcopy()函數}

7.介紹一下except的用法和作用?

答:try…except…except…[else…][finally…]

執行try下的語句,如果引發異常,則執行過程會跳到except語句。對每個except分支順序嘗試執行,如果引發的異常與except中的異常組匹配,執行相應的語句。如果所有的except都不匹配,則異常會傳遞到下一個調用本代碼的最高層try代碼中。

try下的語句正常執行,則執行else塊代碼。如果發生異常,就不會執行

如果存在finally語句,最後總是會執行。

8.Python中pass語句的作用是什麼?

答:pass語句不會執行任何操作,一般作爲佔位符或者創建佔位程序,whileFalse:pass

9.介紹一下Python下range()函數的用法?

答:列出一組數據,經常用在for in range()循環中

10.如何用Python來進行查詢和替換一個文本字符串?

答:可以使用re模塊中的sub()函數或者subn()函數來進行查詢和替換,

格式:sub(replacement, string[,count=0])(replacement是被替換成的文本,string是需要被替換的文本,count是一個可選參數,指最大被替換的數量)

>>> import re
>>>p=re.compile(‘blue|white|red’)
>>>print(p.sub(‘colour’,'blue socks and red shoes’))
colour socks and colourshoes
>>>print(p.sub(‘colour’,'blue socks and red shoes’,count=1))
colour socks and redshoes

subn()方法執行的效果跟sub()一樣,不過它會返回一個二維數組,包括替換後的新的字符串和總共替換的數量

11.Python裏面match()和search()的區別?

答:re模塊中match(pattern,string[,flags]),檢查string的開頭是否與pattern匹配。

re模塊中research(pattern,string[,flags]),在string搜索pattern的第一個匹配值。

>>>print(re.match(‘super’, ‘superstition’).span())
(0, 5)
>>>print(re.match(‘super’, ‘insuperable’))
None
>>>print(re.search(‘super’, ‘superstition’).span())
(0, 5)
>>>print(re.search(‘super’, ‘insuperable’).span())
(2, 7)

12.用Python匹配HTML tag的時候,<.>和<.?>有什麼區別?

答:術語叫貪婪匹配( <.> )和非貪婪匹配(<.?> )

例如:

test
<.*> :
test
<.*?> :

13.Python裏面如何生成隨機數?

答:random模塊

隨機整數:random.randint(a,b):返回隨機整數x,a<=x<=b

random.randrange(start,stop,[,step]):返回一個範圍在(start,stop,step)之間的隨機整數,不包括結束值。

隨機實數:random.random( ):返回0到1之間的浮點數

random.uniform(a,b):返回指定範圍內的浮點數。

14.有沒有一個工具可以幫助查找python的bug和進行靜態的代碼分析?

答:PyChecker是一個python代碼的靜態分析工具,它可以幫助查找python代碼的bug, 會對代碼的複雜度和格式提出警告

Pylint是另外一個工具可以進行codingstandard檢查

15.如何在一個function裏面設置一個全局的變量?

答:解決方法是在function的開始插入一個global聲明:

def f():
    global x

16.單引號,雙引號,三引號的區別

答:單引號和雙引號是等效的,如果要換行,需要符號(),三引號則可以直接換行,並且可以包含註釋

如果要表示Let’s go 這個字符串

單引號:s4 = ‘Let\’s go’

雙引號:s5 = “Let’s go”

s6 = ‘I realy like“python”!’

這就是單引號和雙引號都可以表示字符串的原因了


休息一下

這裏寫圖片描述


下面的代碼輸出什麼?

list = ['a', 'b', 'c', 'd', 'e']
print list[10:]

上面的代碼輸出[],並且不會導致IndexError錯誤

跟你想的一樣,當取列表元素的時候,如果索引值超過了元素的個數(例如在上面的列表中,取list[10])將會導致IndexError錯誤。但是,取一個列表的切片的時候,如果起始索引超過了元素個數,將不會引起IndexError錯誤,僅返回一個空列表。

這一特性將會導致一些非常難於追蹤的bug,因爲在運行時根本沒有錯誤產生。

下面的代碼在Python2中的輸出是什麼?解釋你的答案

def div1(x,y):
    print "%s/%s = %s" % (x, y, x/y)

def div2(x,y):
    print "%s//%s = %s" % (x, y, x//y)

div1(5,2)
div1(5.,2)
div2(5,2)
div2(5.,2.)

另外,在Python3中上面的代碼的輸出有何不同(假設代碼中的print語句都轉化成了Python3中的語法結構)?

在Python2中,代碼的輸出是:

5/2 = 2
5.0/2 = 2.5
5//2 = 2
5.0//2.0 = 2.0

默認情況下,如果兩個操作數都是整數,Python2默認執行整數運算。所以,5/2 結果是2,而5./2結果是2.5

注意你可以通過下面的import語句來覆蓋Python2中的這一行爲

from future import division
還要注意“雙斜槓”(//)操作符將會一直執行整除,忽略操作數的類型。這就是爲什麼5.0//2.0即使在Python2中結果也是2.0

但是在Python3並沒有這一行爲。兩個操作數都是整數時,也不執行整數運算。在Python3中,輸出如下:

5/2 = 2.5
5.0/2 = 2.5
5//2 = 2
5.0//2.0 = 2.0

下面代碼的輸出是什麼?請解釋你的答案

def extendList(val, list=[]):
    list.append(val)
    return list

list1 = extendList(10)
list2 = extendList(123,[])
list3 = extendList('a')

print "list1 = %s" % list1
print "list2 = %s" % list2
print "list3 = %s" % list3

如何修改函數ExtendList的定義才能產生我們希望的行爲?

輸出爲:

list1 = [10, 'a']
list2 = [123]
list3 = [10, 'a']

很多人會錯誤地預計list1等於[10],list3等於[‘a’],認爲extendList函數的list參數在每一次函數被調用時都會被設置爲默認值[]

但是,真實的情況是,默認的list只在函數定義的時候被創建一次。之後不指定list參數地調用extendList函數時,使用的都是同一個list。這是因爲帶默認參數的表達式是在函數定義的時候被計算的,而不是在函數調用時。

所以,list1和list3都是在操作同一個默認list,而list2是在操作它自己創建的一個獨立的list(將自己的空list作爲參數傳遞過去)

extendlist的定義可以這樣定義來達到我們預期的效果:

def extendList(val, list=None):
    if list is None:
        list = []
    list.append(val)
    return list

調用修改後的函數,輸出是:

list1 = [10]
list2 = [123]
list3 = ['a']

下面代碼的輸出是什麼?請解釋你的答案

class Parent(object):
    x = 1

class Child1(Parent):
    pass

class Child2(Parent):
    pass

print Parent.x, Child1.x, Child2.x
Child1.x = 2
print Parent.x, Child1.x, Child2.x
Parent.x = 3
print Parent.x, Child1.x, Child2.x
輸出爲:

1 1 1
1 2 1
3 2 3

讓很多人感到疑惑和驚訝的是,最後一行的輸出竟然不是3 2 1而是3 2 3. 爲什麼修改了Parent.X的值會影響到Child2.x,但是同時又沒有改變Child1.x的值呢?

這個問題的關鍵在於,在python中,類中的變量在內部被當作字典處理。如果一個變量名在當前類的字典中沒有被發現,系統將會在這個類的祖先(例如,它的父類)中繼續尋找,直到找到爲止(如果一個變量名在這個類和這個類的祖先中都沒有,那麼將會引發一個AttributeError錯誤)

因此,在父類中將變量x賦值爲1,那麼x變量將可以被當前類和所有這個類的子類引用。這就是爲什麼第一個print語句輸出爲1 1 1.

接下來,如果它的子類覆蓋了這個值(例如, 當我們執行Child1.x = 2),那麼這個變量的值僅僅在這個子類中發生了改變。這就是爲什麼第二個print語句輸出1 2 1

最後,如果父類改變了這個變量的值(例如,我們執行Parent.x = 3),所有沒有覆蓋這個參數值的子類(在這個例子中覆蓋了參數的就是Child2)都會受到影響,這就是爲什麼第三個print語句的輸出爲3 2 3

下面代碼的輸出是什麼?請解釋你的答案

def multipliers():
    return [lambda x : i * x for i in range(4)]

print [m(2) for m in multipliers()]

怎麼修改multipliers的定義才能達到期望的效果?

上面代碼的輸出是[6, 6, 6, 6](不是[0, 2, 4, 6]).

原因是Python的閉包是延遲綁定(late binding)的。這表明在閉包中使用的變量直到內層函數被調用的時候纔會被查找。結果是,當調用multipliers()返回的函數時,i參數的值會在這時被在調用環境中查找。所以,無論調用返回的哪個函數,for循環此時已經結束,i等於它最終的值3。因此,所有返回的函數都要乘以傳遞過來的3,因爲上面的代碼傳遞了2作爲參數,所以他們都返回了6(即,3 * 2)

(順便提一句,正如在書《The Hitchhiker’s Guide to Python》中提出來的一樣, 有一種廣泛傳播的誤解認爲這個問題和lambda表達式有關,事實並非如此。通過labda表達式產生的函數並沒有什麼特別之處,使用普通的def定義的函數的行爲和lambda表達式產生的函數的行爲是一樣的.)

下面是一些可以繞過這個問題的方法。

方法一是像下面一樣使用Python的生成器(generator)

def multipliers():
     for i in range(4): yield lambda x : i * x 

另一個方法是創造一個閉包,通過使用一個默認參數來立即綁定它的參數

def multipliers():
    return [lambda x, i=i : i * x for i in range(4)]

或者,你也可以使用functools.partial函數:

from functools import partial
from operator import mul

def multipliers():
    return [partial(mul, i) for i in range(4)]

考慮下面的代碼片段:

1. list = [ [ ] ] * 5
2. list  # output?
3. list[0].append(10)
4. list  # output?
5. list[1].append(20)
6. list  # output?
7. list.append(30)
8. list  # output?

第2,4,6,8行的輸出是什麼?解釋你的答案.

輸出如下:

[[], [], [], [], []]
[[10], [10], [10], [10], [10]]
[[10, 20], [10, 20], [10, 20], [10, 20], [10, 20]]
[[10, 20], [10, 20], [10, 20], [10, 20], [10, 20], 30]

下面是解釋:

第一行的輸出憑直覺就能知道,很容易理解。即:list = [ [ ] ] * 5創建了一個元素是5個列表的列表。

但是,這裏要理解的關鍵是,list = [ [ ] ] * 5並沒有創建一個包含5個不同列表的列表。創建的這個列表裏的5個列表,是對同一個列表的引用(a a list of 5 references to the same list)。理解了這些,你就能更好地理解餘下的輸出。

list[0].append(10)將數字10添加到第一個列表。但是由於5個列表是對同一個列表的引用,所以輸出是[[10], [10], [10], [10], [10]]。

同樣的,list[1].append(20)將20追加到第二個列表。但是同樣,由於這5個列表引用同一個列表,所以輸出:[[10, 20], [10, 20], [10, 20], [10, 20], [10, 20]].

相比之下, list.append(30)是將一個全新的元素追加到“外層”的列表,所以產生了這樣的輸出:[[10, 20], [10, 20], [10, 20], [10, 20], [10, 20], 30].

有一個擁有N個元素的列表,用一個列表解析式生成一個新的列表,元素的值同時滿足以下條件:

(a) 偶數,以及
(b) 在原列表中,索引爲偶數
例如,如果list[2]的值是偶數,那麼這個元素應該也被包含在新列表中,因爲它在原列表中的索引也是偶數(即 2). 但是, 如果list[3]是偶數,那這個值不應該被包含在新列表中,因爲它在原列表中的索引是一個奇數。

一個簡單的解法如下:

[x for x in list[::2] if x%2 == 0]

例如,給出下面的列表:

   0   1   2   3    4    5    6    7    8

list = [ 1 , 3 , 5 , 8 , 10 , 13 , 18 , 36 , 78 ]
列表解析式[x for x in list[::2] if x%2 == 0] 會生成:

[10, 18, 78]

這個表達式首先取列表中索引是偶數的數字,然後過濾掉所有的奇數。


這裏寫圖片描述
關注python與web安全

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章