python基礎面試題30問(附帶答案)
1、 閉包
定義:閉包是由函式及其相關的引用環境組合而成的實體(即:閉包=函式+引用環境)(想想Erlang的外層函式傳入一個引數a, 內層函式依舊傳入一個引數b, 內層函式使用a和b, 最後返回內層函式)
程式碼:def ExFunc(n):
sum=n
def InsFunc():
return sum+1
return InsFunc
2、 裝飾器
def debug(func):
def wrapper():
print "[DEBUG]: enter {}()".format(func.__name__)
return func()
return wrapper
@debug
def say_hello():
print "hello!"
3、 迭代器
1、可以直接作用於for迴圈的資料型別
第一類:集合資料型別,如list、tuple、dict、set、str等;
第二類:generator,包括集合定義generator和帶yield的generator(也就是generator function)。
以上這些可以直接作用於for迴圈的物件統稱為可迭代物件:Iterable。
可以使用isinstance()判斷一個物件是否是Iterable物件:
generator不但可以作用於for迴圈,還可以被next()函式不斷呼叫並返回下一個值,直到最後丟擲StopIteration錯誤表示無法繼續返回下一個值了。那麼定義來了,可以被next()呼叫並不斷返回下一個值得物件稱為迭代器(Iterator)
把list、dict、str等Iterable變成Iterator可以使用iter()函式
4、 生成器
為什麼使用生成式:
更容易使用,程式碼量較小記憶體使用更加高效
5、 描述器
描述器的表現
用到三個魔術方法。__get__() __set__() __delete__()
方法簽名如下:
object.__get__(self,instance,owner)
object.__set__(self,instance,value)
object.__delete__(self,instance)
Self指指代當前例項,呼叫者。
Instance是owner的例項。
Owner是屬性所屬的類。
典型的描述器:@Property
作用:訪問類和例項的屬性
6、 內建模組
re(正則)、math(數學)、os(系統)、datetime、sys、json
sys:
sys.argv
功能:在外部向程式內部傳遞引數
sys.exit(n)
功能:執行到主程式末尾,直譯器自動退出,但是如果需要中途退出程式,可以呼叫sys.exit函式,帶有一個可選的整數引數返回給呼叫它的程式,表示你可以在主程式中捕獲對sys.exit的呼叫。(0是正常退出,其他為異常)
sys.path
功能:獲取指定模組搜尋路徑的字串集合,可以將寫好的模組放在得到的某個路徑下,就可以在程式中import時正確找到。
sys.modules
功能:sys.modules是一個全域性字典,該字典是python啟動後就載入在記憶體中。每當程式設計師匯入新的模組,sys.modules將自動記錄該模組。當第二次再匯入該模組時,python會直接到字典中查詢,從而加快了程式執行的速度。它擁有字典所擁有的一切方法。
7、 列表的用法
函式用法:
cmp :比較兩個列表的元素
len :列表元素個數
max :返回列表元素最大值
min :返回列表元素最小值
list :將元組轉化為列表
方法:
List.append() 在列表末尾新增新物件
List.count() 統計某個元素在列表中出現的次數
List.extend() 在列表末尾一次性追加另一個序列中的多個值(用新列表擴充套件原來的列表)
List.index() 從列表中找出某個值第一個匹配項的索引位置
List.insert() 將物件插入列表
List.pop() 移除列表中的一個元素(預設最後一個元素),並且返回該元素的值
List.remove() 移除列表中某個值的第一個匹配項
List.reverse() 反向列表中元素
List.sort() 對原列表進行排序 reverse=False(預設升序)
.join() 將列表轉化為字串
8、 字串用法
內建函式:
Capitalize() 字串第一個大寫
Center() 返回一個原字串居中,並使用空格填充至長度 width 的新字串
Count(str,beg=0,end=len(string)) 返回 str 在 string 裡面出現的次數,如果 beg 或者 end 指定則返回指定範圍內 str 出現的次數
decode(encoding=’utf-8’) 以 encoding 指定的編碼格式解碼 string,如果出錯預設報一個 ValueError 的 異 常 , 除非 errors 指 定 的 是 'ignore' 或 者'replace'
encode(encoding=’utf-8’) 以 encoding 指定的編碼格式編碼 string,如果出錯預設報一個ValueError 的異常,除非 errors 指定的是'ignore'或者'replace'
endswith(obj,beg=0,end=len(string)) 檢查字串是否以 obj 結束,如果beg 或者 end 指定則檢查指定的範圍內是否以 obj 結束,如果是,返回 True,否則返回 False.
expandtabs(tabsize=8) 把字串 string 中的 tab 符號轉為空格,tab 符號預設的空格數是 8。
Format() 格式化字串
Index() 跟find()方法一樣,只不過如果str不在 string中會報一個異常
Isalnum() 如果 string 至少有一個字元並且所有字元都是字母或數字則返回 True,否則返回 False
Isalpha() 如果 string 至少有一個字元並且所有字元都是字母則返回 True,否則返回 False
Isdigit() 如果 string 只包含數字則返回 True 否則返回 False.
Lstrip() 截掉 string 左邊的空格
Replace(str1,str2,num=string.count(str1) 把 string 中的 str1 替換成 str2,如果 num 指定,則替換不超過 num 次
Rstrip() 刪除 string 字串末尾的空格.
Split(str=’’,num=string.count(str)) 以 str 為分隔符切片 string,如果 num 有指定值,則僅分隔 num+ 個子字串
Strip() 在 string 上執行 lstrip()和 rstrip()
9、 排序演算法
氣泡排序:時間複雜度O(n^2)
交換排序的一種。其核心思想是:兩兩比較相鄰記錄的關鍵字,如果反序則交換,直到沒有反序記錄為止。
for i in range(length):
for j in range(i+1, length):
if lis[i] > lis[j]:
self.swap(i, j)
選擇排序:時間複雜度O(n^2)
通過n-i次關鍵字之間的比較,從n-i+1個記錄中選出關鍵字最小的記錄,並和第i(1<=i<=n)個記錄進行交換
for i in range(length):
minimum = i
for j in range(i+1, length):
if lis[minimum] > lis[j]:
minimum = j
if i != minimum:
self.swap(i, minimum)
插入排序:時間複雜度O(n^2)
基本操作是將一個記錄插入到已經排好序的有序表中,從而得到一個新的、記錄數增1的有序表
# 下標從1開始
for i in range(1, length):
if lis[i] < lis[i-1]:
temp = lis[i]
j = i-1
while lis[j] > temp and j >= 0:
lis[j+1] = lis[j]
j -= 1
lis[j+1] = temp
希爾排序:時間複雜度O(n^(3/2))
"""希爾排序"""
lis = self.r
length = len(lis)
increment = len(lis)
while increment > 1:
increment = int(increment/3)+1
for i in range(increment+1, length):
if lis[i] < lis[i - increment]:
temp = lis[i]
j = i - increment
while j >= 0 and temp < lis[j]:
lis[j+increment] = lis[j]
j -= increment
lis[j+increment] = temp
快速排序:時間複雜度O(nlog(n))
快速排序演算法的核心思想:通過一趟排序將待排記錄分割成獨立的兩部分,其中一部分記錄的關鍵字均比另一部分記錄的關鍵字小,然後分別對這兩部分繼續進行排序,以達到整個記錄集合的排序目的
while low < high:
while low < high and lis[high] >= pivot_key:
high -= 1
self.swap(low, high)
while low < high and lis[low] <= pivot_key:
low += 1
self.swap(low, high)
二分法查詢
演算法:二分法查詢適用於資料量較大時,但是資料需要先排好順序。主要思想是:(設查詢的陣列區間為array[low, high])
10、 Socket程式設計
Socket伺服器程式設計
主要包括下面的幾步:
1.開啟socket
2.繫結到一個地址和埠
3.偵聽進來的連線
4.接受連線
5.讀寫資料
Socket客戶端程式設計
主要包括下面的幾步:
1.開啟socket
2.連線到一個地址和埠
3.讀寫資料
Socket型別
Socket函式
11、 TCP/UDP
TCP的優點: 可靠,穩定 TCP的可靠體現在TCP在傳遞資料之前,會有三次握手來建立連線,而且在資料傳遞時,有確認、視窗、重傳、擁塞控制機制,在資料傳完後,還會斷開連線用來節約系統資源。
TCP的缺點: 慢,效率低,佔用系統資源高,易被攻擊 TCP在傳遞資料之前,要先建連線,這會消耗時間,而且在資料傳遞時,確認機制、重傳機制、擁塞控制機制等都會消耗大量的時間,而且要在每臺裝置上維護所有的傳輸連線,事實上,每個連線都會佔用系統的CPU、記憶體等硬體資源。 而且,因為TCP有確認機制、三次握手機制,這些也導致TCP容易被人利用,實現DOS、DDOS、CC等攻擊。
UDP的優點: 快,比TCP稍安全 UDP沒有TCP的握手、確認、視窗、重傳、擁塞控制等機制,UDP是一個無狀態的傳輸協議,所以它在傳遞資料時非常快。沒有TCP的這些機制,UDP較TCP被攻擊者利用的漏洞就要少一些。但UDP也是無法避免攻擊的,比如:UDP Flood攻擊……
UDP的缺點: 不可靠,不穩定 因為UDP沒有TCP那些可靠的機制,在資料傳遞時,如果網路質量不好,就會很容易丟包。
小結TCP與UDP的區別:
1.基於連線與無連線;
2.對系統資源的要求(TCP較多,UDP少);
3.UDP程式結構較簡單;
4.流模式與資料報模式 ;
5.TCP保證資料正確性,UDP可能丟包,TCP保證資料順序,UDP不保證。
什麼時候應該使用TCP: 當對網路通訊質量有要求的時候,比如:整個資料要準確無誤的傳遞給對方,這往往用於一些要求可靠的應用,比如HTTP、HTTPS、FTP等傳輸檔案的協議,POP、SMTP等郵件傳輸的協議。 在日常生活中,常見使用TCP協議的應用如下: 瀏覽器,用的HTTP FlashFXP,用的FTP Outlook,用的POP、SMTP Putty,用的Telnet、SSH QQ檔案傳輸 ………… 什麼時候應該使用UDP: 當對網路通訊質量要求不高的時候,要求網路通訊速度能儘量的快,這時就可以使用UDP。 比如,日常生活中,常見使用UDP協議的應用如下: QQ語音 QQ視訊 TFTP ……
有些應用場景對可靠性要求不高會用到UPD,比如長視訊,要求速率
12、 HTTP/HTTPS協議
HTTP:是網際網路上應用最為廣泛的一種網路協議,是一個客戶端和伺服器端請求和應答的標準(TCP),用於從WWW伺服器傳輸超文字到本地瀏覽器的傳輸協議,它可以使瀏覽器更加高效,使網路傳輸減少。
HTTPS:是以安全為目標的HTTP通道,簡單講是HTTP的安全版,即HTTP下加入SSL層,HTTPS的安全基礎是SSL,因此加密的詳細內容就需要SSL。
HTTPS協議的主要作用可以分為兩種:一種是建立一個資訊保安通道,來保證資料傳輸的安全;另一種就是確認網站的真實性。
區別
1、https協議需要到ca申請證書,一般免費證書較少,因而需要一定費用。
2、http是超文字傳輸協議,資訊是明文傳輸,https則是具有安全性的ssl加密傳輸協議。
3、http和https使用的是完全不同的連線方式,用的埠也不一樣,前者是80,後者是443。
4、http的連線很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網路協議,比http協議安全。
13、 高階函式
Map()、filter()、zip()、reduce()、sorted()、lambda函式
14、 深/淺拷貝
淺拷貝:拷貝表面層,更深的層次引用原來地址的
深拷貝:拷貝所有,記憶體中開闢新地址
15、 面向物件程式設計(OOP)
16、 元類
所有類的父類,定義的新類可以看成元類的例項
17、 正則
功能函式:
compile() 編譯正則表示式模式,返回一個物件的模式
match() 只匹配字串的開始,如果開始不匹配,函式返回None
search() 在整個字串中尋找,找到返回,匹配不成功返回None
findall() 遍歷匹配,可以獲取字串中所有匹配的字串,返回一個列表
finditer() 搜尋string,返回一個順序訪問每一個匹配結果(Match物件)的迭代器。找到 RE 匹配的所有子串,並把它們作為一個迭代器返回
貪婪匹配和費貪婪匹配
前面的*,+,?等都是貪婪匹配,也就是儘可能匹配,後面加?號使其變成惰性匹配
\d 數字:[0-9]
\D 非數字:[^\d]
\s 匹配任何空白字元:[<空格>\t\r\n\f\v]
\S 非空白字元:[^\s]
\w 匹配包括下劃線在內的任何字字元:[A-Za-z0-9_]
\W 匹配非字母字元,即匹配特殊字元
\A 僅匹配字串開頭,同^
\Z 僅匹配字串結尾,同$
\b 匹配\w和\W之間,即匹配單詞邊界匹配一個單詞邊界,也就是指單詞和空格間的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的'er'。
\B [^\b]
. 匹配任意除換行符"\n"外的字元(在DOTALL模式中也能匹配換行符
\ 轉義字元,使後一個字元改變原來的意思
l 匹配前一個字元0或多次
+ 匹配前一個字元1次或無限次
? 匹配一個字元0次或1次
18、 __new__ 和 __init__的區別
1、 繼承自object的新式類才有__new__
2、 __new__至少要有一個引數cls,代表當前類,此引數在例項化時由Python直譯器自動識別
3、 __new__必須要有返回值,返回例項化出來的例項,這點在自己實現__new__時要特別注意,可以return父類(通過super(當前類名, cls))__new__出來的例項,或者直接是object的__new__出來的例項
4、 __init__有一個引數self,就是這個__new__返回的例項,__init__在__new__的基礎上可以完成一些其它初始化的動作,__init__不需要返回值
19、 執行緒、程序和協程
執行緒:輕量級程序,執行緒是程序中的一個實體,是被系統獨立排程和分派的基本單位,執行緒自己不擁有系統資源,只擁有一點兒在執行中必不可少的資源,但它可與同屬一個 程序的其它執行緒共享程序所擁有的全部資源
使用threading這個高階模組
多個執行緒訪問同一資源時需要加執行緒鎖lock
獲取鎖:lock.acquire()
釋放鎖:lock.release()
程序:程序是一個實體。每一個程序都有它自己的地址空間
建立程序的類:process
協程:一個程式可以包含多個協程,可以對比與一個程序包含多個執行緒,因而下面我們來比較協程和執行緒。我們知道多個執行緒相對獨立,有自己的上下文,切換受系統控制;而協程也相對獨立,有自己的上下文,但是其切換由自己控制,由當前協程切換到其他協程由當前協程來控制。
優點:IO資源、減少callback的使用
用第三方庫 gevent 來支援協程。gevent用到的主要模式是greenlet
20、 記憶體管理
1、 Python引入了一個機制:引用計數
2、 垃圾回收機制:當引用計數為0時,呼叫__del__方法
注意:
1、垃圾回收時,Python不能進行其它的任務,頻繁的垃圾回收將大大降低Python的工作效率;
2、Python只會在特定條件下,自動啟動垃圾回收(垃圾物件少就沒必要回收)
3、當Python執行時,會記錄其中分配物件(object allocation)和取消分配物件(object deallocation)的次數。當兩者的差值高於某個閾值時,垃圾回收才會啟動。
3、記憶體池機制
Python中有分為大記憶體和小記憶體:(256K為界限分大小記憶體)
1、大記憶體使用malloc進行分配
2、小記憶體使用記憶體池進行分配
3、Python的記憶體池(金字塔)
21、 random.shuffle(lst):將列表中的元素打亂,洗牌
random.random():生成一個0-1之間的隨機浮點數.
random.uniform(a, b):生成[a,b]之間的浮點數.
22、 實現單例模式
- 使用__new__方法
class Singleton(object):
def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
orig = super(Singleton, cls)
cls._instance = orig.__new__(cls, *args, **kwargs)
rerurn cls._instance
class A(Singleton):
pass
# 類A即為單例類
2、 使用裝飾器
def singleton(cls):
instance = {}
def wapper():
if cls not in instance:
instance[cls] = cls(*args, **kwargs)
return instance[cls]
return wapper
@singleton
class C:
pass
# 類C即為單例類
23、 實現一個斐波那契數列的生成器
# def fib(n):
# a, b = 0, 1
# for _ in range(n):
# a, b = b, a + b
# yield a
#
# def main():
# for val in fib(20):
# print(val)
# if __name__ == '__main__':
# main()
24、 一行帶實現1-100之和
sum(range(0,100))
25、 python中的GIL
26、 列表去重(通過集合set)
27、 Python2和python3的區別
1、 print
p2中print當做一個類使用,p3中print當做一個函式使用
2、 input()
p2中input接收到的型別為int,p3中input接收到的型別為str
3、 Unicode
Python 2 有 ASCII str() 型別,unicode() 是單獨的,不是 byte 型別
4、 不等運算子
Python 2.x中不等於有兩種寫法 != 和 <>
Python 3.x中去掉了<>, 只有!=一種寫法
5、 資料型別
Py3.X去除了long型別,現在只有一種整型——int,
新增了bytes型別,對應於2.X版本的八位串
28、 python中的斷言
關鍵字:assert
Assert後面跟合法的表示式,當表示式為True是,不做任何操作,為False時回丟擲異常,assert可以快速定位程式碼中的錯誤
29、 with方法開啟檔案實現了關閉的功能
30、 Linux常用命令
ls、cd、vim、mkdir、pwd、rm、rmdir、mv、cp、cat、find、head、history、tail、grep、chmod、tar、ps、top、kill、free、