基礎
1.列出 5 個常用 Python 標準庫?
- os:與操作系統相關聯的函數,path 的 join()、split()、exists();mkdir()、listdir()、rename()、system() 等
- sys:通常用於命令行參數
- re:正則匹配,match、search、findall、sub、split、complie 等
- math:數學運算,三角函數(sin, cos, tan…)、向上向下取整(ceil, floor)、開方(sqrt) 等
- random:隨機模塊,random、randint、randrange 等
- calendar:日曆模塊
- time:時間模塊,時間戳
time.time
、線程休眠time.sleep()
等 - datetime:處理日期時間
2.Python 內建數據類型有哪些?
- Number(數字)
- String(字符串)
- List(列表)
- Tuple(元組)
- Set(集合)
- Dictionary(字典)
3.簡述 with 方法打開處理文件幫我我們做了什麼?
打開文件在進行讀寫的時候可能會出現一些異常狀況,如果按照常規的 f.open 寫法,我們需要 try, except, finally… 做異常判斷,並且文件最終不管遇到什麼情況,都要執行 finally f.close() 關閉文件,with 方法幫我們實現了 finally 中 f.close()
4.列出 Python 中可變數據類型和不可變數據類型,爲什麼?
可變數據類型更改後地址不發生改變,不可變數據類型更改後地址發生改變
可變:
- 列表 (list)
- 字典 (dict)
- 集合 (set)
不可變:
- 數字 (int, float)
- 布爾 (bool)
- 字符串 (str)
- 集合 (set)
5.Python 獲取當前日期?
import datetime
now_time = datetime.datetime.now()
# 或者
import time
now_time = time.localtime(time.time())
6.統計字符串每個單詞出現的次數
(1)setdefault()的方法判斷
message = 'It was a bright cold day in April, and the clocks were striking thirteen.'
count = {}
for character in message:
count.setdefault(character, 0) # 方法調用確保了鍵存在於 count 字典中(默認值是 0)
count[character] = count[character] + 1
print(count)
(2)傳統方法
count = {}
for i in message:
if i not in count:
count[i] = 1
else:
count[i] += 1
print(count)
(3)Counter方法
from collections import Counter
count= Counter(message)
print(count)
7.用 Python 刪除文件和用 linux 命令刪除文件方法
- Python:
os.remove(path)
- Linux:
rm -f path
8.寫一段自定義異常代碼
# 你隨便輸入一句話 看我喜不喜歡 不喜歡我就拋出異常
# 自定義異常類
class UnlikeError(BaseException):
def __init__(self,msg,text):
self.msg = msg
self.text = text
# 函數中可能拋出異常
def hello():
text = input("輸入一段話:")
if text == "你真帥":
print("你說得對!")
else:
raise UnlikeError("你再看看...","另一個參數")
# 捕獲異常
try:
hello()
# 獲取異常對象
except UnlikeError as e:
print(e.text)
9.舉例說明異常模塊中 try, except, else, finally… 的相關意義
- try, except, else… :沒有捕獲到異常,則執行 else 語句
- try, except, finally… :不管是否捕獲到異常,都執行 finally 語句
try:
num = 100
print(num)
except NameError as errorMsg:
print('產生錯誤了:%s'% errorMsg)
else:
print('沒有捕捉到異常,則執行該語句')
try:
num = 100
print(num)
except NameError as errorMsg:
print('產生錯誤了:%s'% errorMsg)
finally:
print('不管是否捕捉到異常,都執行該語句')
運行結果如下:
100
沒有捕捉到異常,則執行該語句
100
不管是否捕捉到異常,都執行該語句
10.遇到 bug 如何處理
- 使用 debug 模式調試
- 使用 try, except, else… 或 try, except, finally… 捕捉異常
語言特性
1.談談對 Python 和其他語言的區別
Python 是一門語法簡潔優美,功能強大無比,應用領域非常廣泛,具有強大完備的第三方庫,他是一門強類型的可移植、可擴展,可嵌入的解釋型編程語言,屬於動態語言。
-
語言特點
簡潔、優雅,省略了各種大括號和分號,還有一些關鍵字、類型說明 -
語言類型
解釋型語言,運行的時候是逐行解釋並運行,所以調試代碼很方便,開發效率高 -
第三方庫
python 是開源的,並且 python 的最近幾年發展迅猛,應用領域很多。比如:Web、運維、自動化測試、爬蟲、數據分析、人工智能;Python 具有非常完備的第三方庫。 -
缺點就是 Python 的執行速度不夠快
python 是一門解釋型語言,所以它的速度相較於 C/C++ 這種編譯型語言會慢一些,但是並不影響使用
因爲現在的硬件配置都非常的高,基本沒什麼影響,除非是一些實時性比較強的程序可能會受到一些影響,但是也是有解決辦法的,可以嵌入 C/C++代碼
2.簡述解釋型和編譯型編程語言
-
解釋型語言編寫的程序不需要編譯,在執行的時候,專門有一個解釋器能夠將我們寫的代碼翻譯成機器語言,每個語句都是執行的時候才翻譯。這樣解釋型語言每執行一次就要翻譯一次,效率比較低。
-
編譯型語言寫的程序執行之前,需要一個專門的編譯過程,通過編譯系統,把源高級程序編譯成爲機器語言文件,翻譯只做了一次,運行時不需要翻譯,所以編譯型語言的程序執行效率高,但也不能一概而論,部分解釋型語言的解釋器通過在運行時動態優化代碼,甚至能夠使解釋型語言的性能超過編譯型語言。
3.Python 的解釋器種類以及相關特點?
- CPython
C語言開發的,使用最廣的解釋器 - IPython
基於 CPython 之上的一個交互式計時器,交互方式增強,功能和 CPython 一樣 - PyPy
目標是執行效率,採用 JIT 技術,對 python 代碼進行動態編譯,提高執行效率 - JPython
運行在 Java 上的解釋器,直接把 python 代碼編譯成 Java 字節碼執行 - IronPython
運行在微軟 .NET 平臺上的解釋器,把 python 編譯成. NET 的字節碼
4.說說你知道的 Python3 和 Python2 之間的區別?
- print 在 Python3 中是函數必須加括號;Python2 中 print 爲 class。
- Python2 中使用 xrange;Python3 使用 range。
- Python2 中默認的字符串類型默認是 ASCII;Python3 中默認的字符串類型是 Unicode。
- Python2 中1/2的結果是整型 (0);Python3 中是浮點類型 (0.5),不再區分 int 和 long。
- Python2 中聲明元類:
_metaclass_ = MetaClass
;
Python3 中聲明元類:class newclass(metaclass = MetaClass): pass
詳細瞭解可參考這篇文章:點此跳轉
5.Python3 和 Python2 中 int 和 long 區別?
Python2 有 int 和 long 類型。int 類型最大值不能超過 sys.maxint,而且這個最大值是平臺相關的。可以通過在數字的末尾附上一個L來定義長整型,顯然,它比 int 類型表示的數字範圍更大。在 Python3 裏,只有一種整數類型 int,大多數情況下,和 Python2中的長整型類似。
6.xrange 和 range 的區別?
python3 中不存在 python2 的 xrange();python3 的 range 就是 python2 的 xrange。
- 在 python2 中,range 返回一個列表,即 range(3) 返回 [0,1,2],
而 xrange 返回一個 xrange 對象,即 xrange(3) 返回 iterator 對象,它與 Java 迭代器類似,並在需要時生成數字。 - 如果我們需要多次迭代相同的序列,我們更喜歡 range(),因爲 range 提供了一個靜態列表。而 xrange() 每次重建序列。
- xrange() 不支持切片和其他列表方法。
- xrange() 的優點是,當任務迭代大範圍時,它可以節省內存。
- 在 python3 中,範圍函數現在執行 xrange 在 python 2 中的功能,因此爲了保持代碼的可移植性,我們可能希望堅持使用範圍。所以 python 3 的範圍函數是來自 python 2 的 xrange。
編碼規範
7.什麼是 PEP8?
PEP 是 Python Enhancement Proposal 的縮寫,翻譯過來就是 Python 增強建議書;
PEP8 是 python 的一種編碼規範,具體如下:
- 縮進。4個空格的縮進(編輯器都可以完成此功能),不使用 tab,更不能混合使用 tab 和空格。
- 每行最大長度79,換行可以使用反斜槓,最好使用圓括號。換行點要在操作符的後邊敲回車。
- 類和 top-level 函數定義之間空兩行;類中的方法定義之間空一行;函數內邏輯無關段落之間空一行;其他地方儘量不要再空行。
- 模塊導入的順序:按標準、三方和自己編寫順序依次導入,之間空一行。
- 不要在一句 import 中多個庫,比如
import os, sys
不推薦 - 避免不必要的空格
- 註釋必須要有
- 函數命名要遵循規範
- 儘可能使用 ‘is’ ‘is not’ 取代 ‘==’,比如
if x is not None
要優於if x
。 - 使用基於類的異常,每個模塊或包都有自己的異常類,此異常類繼承自 Exception。
- 異常中 try 的代碼儘可能少。
8.瞭解 Python 之禪麼?
適當回答幾條即可:點此跳轉
9.瞭解 docstring 麼?
-
DocStrings 文檔字符串是一個重要工具,用於解釋文檔程序,幫助你的程序文檔更加簡單易懂。
我們可以在函數體的第一行使用一對三個單引號 ‘’’ 或者一對三個雙引號 “”" 來定義文檔字符串。
你可以使用__doc__
(注意雙下劃線)調用函數中的文檔字符串屬性。 -
DocStrings 文檔字符串使用慣例:它的首行簡述函數功能,第二行空行,第三行爲函數的具體描述。
10.瞭解類型註解麼?
用 : 類型 的形式指定函數的參數類型,用 -> 類型 的形式指定函數的返回值類型。
例如:
def add(x:int, y:int) -> int:
return x + y
然後特別要強調的是,Python 解釋器並不會因爲這些註解而提供額外的校驗,沒有任何的類型檢查工作。也就是說,這些類型註解加不加,對你的代碼來說沒有任何影響
詳細瞭解可參考:點此跳轉
11.例舉你知道 Python 對象的命名規範,例如方法或者類等?
適當回答幾條即可:點此跳轉
12.Python 中的註釋有幾種?
- 單行註釋:
#
- 多行註釋:
""" """
13.如何優雅的給一個函數加註釋?
函數註釋通常在 def 語句下方,第一行表示函數用法,接下來對函數接受的參數進行解釋,最後對函數的返回值進行註釋,方便他人理解函數的用法
詳細瞭解可參考這篇文章:點此跳轉
14.如何給變量加註釋?
- 單行註釋:
#
- 多行註釋:
""" """
15.Python 代碼縮進中是否支持 Tab 鍵和空格混用。
需要統一使用 tab 或統一使用空格,不能混用
Python 是一門用空格縮進來區分代碼層次的語言,其實 Python 並沒有強制要求你用 Tab 縮進或者用空格縮進,甚至空格按幾個都沒有強制要求,但在 PEP8 中建議了使用4個空格作爲縮進
16.是否可以在一句 import 中導入多個庫?
可以是可以,但是不推薦。因爲一次導入多個模塊可讀性不是很好,所以一行導入一個模塊會比較好。同樣的儘量少用 from modulename import *,因爲判斷某個函數或者屬性的來源有些困難,不方便調試,可讀性也降低了。
17.在給 py 文件命名的時候需要注意什麼?
給文件命名的時候不要和標準庫庫的一些模塊重複,比如 abc。 另外要名字要有意義,不建議數字開頭或者中文命名。
18.例舉幾個規範 Python 代碼風格的工具:
- pylint
- flake8
- YAPF,谷歌開發的代碼規範工具
- Black,依賴 Python3.6+ 的第三方庫,可以直接將原代碼變爲符合 PEP8 標準的代碼
數據類型
字符串
19.列舉 Python 中的基本數據類型?
- 整型 int
- 浮點型 float
- 布爾型 bool
- 字符串 str
20.如何區別可變數據類型和不可變數據類型?
可變數據類型更改後地址不發生改變,不可變數據類型更改後地址發生改變
21.將 “hello world” 轉換爲首字母大寫 "Hello World"
strA = 'hello world'
print(strA.title())
# 或
print(strA.capitalize())
22.如何檢測字符串中只含有數字?
使用 isdigit()
函數,返回一個 True 或 False
23.將字符串"ilovechina"進行反轉
- 使用切片:
"ilovechina"[::-1]
- 使用
reversed()
方法:''.join(reversed('ilovechina'))
注意:
- reverse() :函數用於反向列表中元素,僅適用於列表
- reversed():函數是返回序列 seq 的反向訪問的迭代子。參數可以是列表,元組,字符串
24.Python 中的字符串格式化方式你知道哪些?
- 使用 % 號
'Hey %s, there is a 0x%x error!' % (name, errno)
'Hey %(name)s, there is a 0x%(errno)x error!' % {"name": name, "errno": errno }
- 使用 format()
'Hello, {}'.format(name)
'Hey {name}, there is a 0x{errno:x} error!'.format(name=name, errno=errno)
- 字符串插值/f-Strings(Python 3.6+)
f'Hello, {name}!'
25.有一個字符串開頭和末尾都有空格,比如“ adabdw ”,要求寫一個函數把這個字符串的前後空格都去掉。
- 使用 replace() 方法
" adabdw ".replace(" ", "")
將空格替換爲空 - 使用切片
" adabdw "[1:7]
26.獲取字符串”123456“最後的兩個字符。
"123456"[4:]
或者 "123456"[-2:]
27.一個編碼爲 GBK 的字符串 S,要將其轉成 UTF-8 編碼的字符串,應如何操作?
a= "S".encode("gbk").decode("utf-8",'ignore')
print(a)
28
(1).s="info:xiaoZhang 33 shandong"
,用正則切分字符串輸出 ["info", "xiaoZhang", "33", "shandong"]
(2).a = "你好 中國 "
,去除多餘空格只留一個空格。
- 使用 replace() 方法
"你好 中國 ".replace(" ", "")
將空格替換爲空
29
(1).怎樣將字符串轉換爲小寫
strA = "ARHststh"
print(strA.lower())
(2).單引號、雙引號、三引號的區別?
三種引號都表示字符串
- 單引號表示的字符串裏可包含雙引號,當然不能包含單引號
- 雙引號表示的字符串裏可以包含單引號,字符串都只能有一行
- 三個引號能包含多行字符串,同時常常出現在函數的聲明的下一行,來註釋函數的功能,與衆不同的地方在於,這個註釋作爲函數的一個默認屬性,可以通過
函數名.__doc__
來訪問
列表
30.已知 AList = [1, 2, 3, 1, 2]
,對 AList 列表元素去重,寫出具體過程。
AList = [1, 2, 3, 1, 2]
print(list(set(AList)))
31.如何實現 "1,2,3"
變成 [“1”,“2”,“3”]
32.給定兩個 list,A 和 B,找出相同元素和不同元素
A=[1,2,3,4,5,6,7,8,9]
B=[1,3,5,7,9]
print('A、B中相同元素:')
print(set(A)&set(B))
print('A、B中不同元素:')
print(set(A)^set(B))
33.[[1, 2], [3, 4], [5, 6]]
一行代碼展開該列表,得出 [1, 2, 3, 4, 5, 6]
1)利用推導式運行過程:for i in a ,每個 i 是 [1, 2], [3, 4], [5, 6], for j in i,每個 j 就是1, 2, 3, 4, 5, 6, 合併後就是結果
a=[[1,2],[3,4],[5,6]]
x=[j for i in a for j in i] #這個的解析過程是:從 a 中取出每一個值付給 i,然後從 i 中取出每一個值賦值給 j 然後輸出 j 的結果
print(x) # [1, 2, 3, 4, 5, 6]
2)將列表轉成 numpy 矩陣,通過 numpy 的flatten()方法
import numpy as np
b=np.array(a).flatten().tolist()
print(b)
3)j for i in a for j in i等於:
list=[]
for i in a:
for j in i:
list.append(j)
print(list)
34.合併列表 [1, 5, 7, 9]
和 [2, 2, 6, 8]
listA = [1, 5, 7, 9]
listB = [2, 2, 6, 8]
listA.extend(listB)
print(listA)
35.如何打亂一個列表的元素?
import random
a = [1, 2, 3, 4, 5]
random.shuffle(a)
print(a)
字典
36.字典操作中 del 和 pop 有什麼區別
-
del() 函數無返回值
del dict
刪除字典 dict,但這會引發一個異常,因爲用執行 del 操作後字典不再存在
del dict['Name']
刪除字典 dict 鍵 ‘Name’ -
pop() 函數有返回值,即刪除的那個值
pop(key[,default])
刪除字典給定鍵 key 所對應的值,返回值爲被刪除的值。key 值必須給出。 否則,返回 default 值。
37.按照字典的內的年齡排序
d1 = [
{'name': 'alice', 'age':38},
{'name': 'bob', 'age':18},
{'name': 'carl', 'age':28},
]
使用 sort 排序:
d1.sort(key=lambda x: x['age'])
38.請合併下面兩個字典 a = {“A”: 1, “B”: 2}, b = {“C”: 3, “D”: 4}
-
使用dict(a,**b)方法
a = {"A": 1, "B": 2} b = {"C": 3, "D": 4} print(dict(a, **b))
-
使用update()函數
a = {"A": 1, "B": 2} b = {"C": 3, "D": 4} c = {} c.update(a) c.update(b) print(c)
-
遍歷 key, value,轉換成列表,再做加法,刪除列表轉換字典的方法 d.items()
e = dict(list(a.items()) + list(b.items())) print(e)
39.如何使用生成式的方式生成一個字典,寫一段功能代碼。
40.如何把元組 (“a”, “b”) 和元組 (1, 2),變爲字典 {“a”: 1, “b”: 2}
print(dict(zip(("a", "b"), (1, 2))))
綜合
41.Python 常用的數據結構的類型及其特性?
- 列表 list:線性;格式爲 [123, “abc”];可以通過索引訪問元素,對所有元素的訪問叫做遍歷
- 元組 tuple:線性;格式爲 (123, “abc”),一個元素也需要逗號 (123, );和 list 很相似,但不能修改,只能查找 index、統計 count
- 字典 dict:非線性;格式爲鍵值對 {“name”: “jack”, “age”: 18};無順序,鍵不重複、值可以重複,根據鍵取值
- 集合 set:非線性;格式爲 (123, “abc”);非線性、無順序、不重複,可用來去重
42.如何交換字典 {“A”: 1,“B”: 2}
的鍵和值?
A: {1: 0, 2: 0, 3: 0}
B: {"a": 0, "b": 0, "c": 0}
C: {(1, 2): 0, (2, 3): 0}
D: {[1, 2]: 0, [2, 3]: 0}
43.Python 裏面如何實現 tuple 和 list 的轉換?
listA = [1, 2, 3]
tupleA = tuple(listA)
tupleB = (123, )
listB = list(tupleB)
44.我們知道對於列表可以使用切片操作進行部分元素的選擇,那麼如何對生成器類型的對象實現相同的功能呢?
使用自帶的 itertools 庫進行實現,具體實現方式 itertools.islice(生成器對象,起始位置,結束位置),即可實現切片功能
45.請將 [i for i in range(3)] 改成生成器
iter(range(3))
46.a=“hello” 和 b=“你好” 編碼成 bytes 類型
a.encode()
b.encode()
47.下面的代碼輸出結果是什麼?
a = (1, 2, 3, [4, 5, 6, 7], 8)
a[2] = 2
元組爲不可變數據類型,所以會報錯:TypeError: 'tuple' object does not support item assignment
48.下面的代碼輸出的結果是什麼?
a = (1, 2, 3, [4, 5, 6, 7], 8)
a[3][0] = 2
print(a)
結果爲:(1, 2, 3, [2, 5, 6, 7], 8)
操作類題目
49.Python 交換兩個變量的值
a = 123
b = "abc"
a, b = b, a
print(a, b) # abc 123
50.在讀文件操作的時候會使用 read、readline 或者 readlines,簡述它們各自的作用
- read()方法:read([size])方法從文件當前位置起讀取size個字節;若無參數size,則表示讀取至文件結束爲止,它範圍爲字符串對象
- readline()方法:該方法每次讀出一行內容,所以,讀取時佔用內存小,比較適合大文件,該方法返回一個字符串對象。
- readlines()方法:讀取整個文件所有行,保存在一個列表(list) 變量中,每行作爲一個元素,但讀取大文件會比較佔內存
51.json 序列化時,可以處理的數據類型有哪些?如何定製支持 datetime 類型?
字符串、數字(整數和浮點數)、字典、列表、布爾值、None。使用 strftime 將 datetime 格式化爲標準字符串類型即可
52.json 序列化時,默認遇到中文會轉換成 unicode,如果想要保留中文怎麼辦?
使用 json.dumps 函數時,添加參數 ensure_ascii=False,如果想顯示的更美觀,可以添加 indent=2 參數,會在每個 key 值前添加兩個空格
53.有兩個磁盤文件 A 和 B,各存放一行字母,要求把這兩個文件中的信息合併(按字母順序排列),輸出到一個新文件 C 中。
讀取兩個文件,利用 split 函數將字符串切割成列表,再將兩個列表合併,利用 sort 函數對合並後的列表進行排序,最後將列表內容拼接成字符串寫入即可
54.如果當前的日期爲 20190530,要求寫一個函數輸出 N 天后的日期,(比如 N 爲 2,則輸出 20190601)。
利用自帶的 datetime 庫即可實現
55.寫一個函數,接收整數參數 n,返回一個函數,函數的功能是把函數的參數和 n 相乘並把結果返回。
def fun(n):
def fun1(n, arg):
return n * arg
return fun1(n)
56.下面代碼會存在什麼問題,如何改進?
def strappend(num):
str = "first"
for i in range(num):
str += str(i)
return str
會報類型錯誤:TypeError: 'str' object is not callable
,沒有對 num 進行校驗,num 應該爲一整數,添加一個 type 類型校驗
57.一行代碼輸出 1-100 之間的所有偶數。
print(list(i for i in range(1, 101) if i%2 == 0))
58.with 語句的作用,寫一段代碼?
常用於打開文本後的自動關閉,例如:
with open("file_name", 'w') as f:
...
59.python 字典和 json 字符串相互轉化方法
使用 json 庫:
- 字典 -> json:json.dumps(dict)
- json -> 字典:json.loads(json_file)
60.請寫一個 Python 邏輯,計算一個文件中的大寫字母數量
with open(file_name, 'r') as f:
count = 0
for i in f.read():
if i.isupper():
count += 1
print('大寫字母數量爲%d'%count)
61. 請寫一段 Python連接 Mongo 數據庫,然後的查詢代碼。
import pymongo
db_configs = {
'type': 'mongo',
'host': '地址',
'port': '端口',
'user': 'spider_data',
'passwd': '密碼',
'db_name': 'spider_data'
}
class Mongo():
def __init__(self, db=db_configs["db_name"], username=db_configs["user"],
password=db_configs["passwd"]):
self.client = pymongo.MongoClient(f'mongodb://{db_configs["host"]}:db_configs["port"]')
self.username = username
self.password = password
if self.username and self.password:
self.db1 = self.client[db].authenticate(self.username, self.password)
self.db1 = self.client[db]
def find_data(self):
# 獲取狀態爲 0 的數據
data = self.db1.test.find({"status": 0})
gen = (item for item in data)
return gen
if __name__ == '__main__':
m = Mongo()
print(m.find_data())
62.說一說 Redis 的基本類型。
- String
- Hash
- List
- Set
- ZSet
參考這篇文章:點此跳轉
63. 請寫一段 Python連接 Redis 數據庫的代碼。
import redis
class Database:
def __init__(self):
self.host = 'localhost'
self.port = 6379
def write(self,website,city,year,month,day,deal_number):
try:
key = '_'.join([website,city,str(year),str(month),str(day)])
val = deal_number
r = redis.StrictRedis(host=self.host,port=self.port)
r.set(key,val)
except Exception, exception:
print exception
def read(self,website,city,year,month,day):
try:
key = '_'.join([website,city,str(year),str(month),str(day)])
r = redis.StrictRedis(host=self.host,port=self.port)
value = r.get(key)
print value
return value
except Exception, exception:
print exception
if __name__ == '__main__':
db = Database()
db.write('meituan','beijing',2013,9,1,8000)
db.read('meituan','beijing',2013,9,1)
上面操作是先寫入一條數據,然後再讀取,如果寫入或者讀取數據太多,那麼我們最好用批處理,這樣效率會更高。
import redis
import datetime
class Database:
def __init__(self):
self.host = 'localhost'
self.port = 6379
self.write_pool = {}
def add_write(self,website,city,year,month,day,deal_number):
key = '_'.join([website,city,str(year),str(month),str(day)])
val = deal_number
self.write_pool[key] = val
def batch_write(self):
try:
r = redis.StrictRedis(host=self.host,port=self.port)
r.mset(self.write_pool)
except Exception, exception:
print exception
def add_data():
beg = datetime.datetime.now()
db = Database()
for i in range(1,10000):
db.add_write('meituan','beijing',2013,i,1,i)
db.batch_write()
end = datetime.datetime.now()
print end-beg
if __name__ == '__main__':
add_data()
參考這篇文章:點此跳轉
64. 請寫一段 Python 連接 MySQL 數據庫的代碼。
import MySQLdb
conn=MySQLdb.connect(host='127.0.0.1',port=3306,user='root',passwd='199331',db='test',charset='utf8')
cur=conn.cursor()
cur.execute("""
create table if not EXISTS user
(
userid int(11) PRIMARY KEY ,
username VARCHAR(20)
)
""")
for i in range(1,10):
cur.execute("insert into user(userid,username) values('%d','%s')" %(int(i),'name'+str(i)))
conn.commit()
cur.close()
conn.close()
65.瞭解 Redis 的事務麼?
Redis 中的事務提供了一種將多個命令請求打包,然後一次性、順序性執行多個命令的機制,並且在事務指向期間,服務器不會中斷事務而改去執行其他客戶端的命令請求,它會將事務中的所有命令都執行完畢,然後纔去處理其他客戶端的請求。
參考這篇文章:點此跳轉
66.瞭解數據庫的三範式麼?
參考這篇文章:點此跳轉
67.瞭解分佈式鎖麼?
多進程併發執行任務時,需要保證任務的有序性或者唯一性,所以就要用到分佈式鎖
- 同一時刻只能存在一個鎖
- 需要解決意外死鎖問題,也就是鎖能超時自動釋放
- 支持主動釋放鎖
68.用 Python 實現一個 Reids 的分佈式鎖的功能。
參考文章:點此跳轉
69.寫一段 Python 使用 Mongo 數據庫創建索引的代碼。
下面的代碼給 user 的 user_name 字段創建唯一索引:
import pymongo
mongo = pymongo.Connection('localhost')
collection = mongo['database']['user']
collection.ensure_index('user_name', unique=True)
高級特性
70.函數裝飾器有什麼作用?請列舉說明?
裝飾器可以在不修改函數的情況下,對函數的功能進行補充,例如對函數接受的參數進行檢查
更加詳細的內容:點此跳轉
71.Python 垃圾回收機制?
python 採用的是引用計數機制爲主,標記-清除和分代收集兩種機制爲輔的策略
最簡單的,Python 每個變量上都有一個引用計數器,當引用計數器爲0時,自動銷燬變量。複雜一些的,例如存在互相引用的情況,這時 Python 依靠兩個鏈表(標記-清除算法)進行垃圾回收。點擊這裏獲得更詳細的資料
72.魔法函數 __call__
怎麼使用?
__call__
是將類創建爲一個實例進行調用,多用在類裝飾器中。可以將邏輯代碼寫在 __call__
下,不需要實例化類也可直接使用其中的代碼。
73.如何判斷一個對象是函數還是方法?
可以使用 type() 函數進行判斷,函數與方法本質上沒有差別,僅僅通過是否與類進行綁定進行區分。綁定後通過類實例化進行調用則爲方法,未綁定直接調用即爲函數。
74.@classmethod
和 @staticmethod
用法和區別
- classmethod 必須實例化類以後才能使用,同時第一個參數由 self 變化爲 cls
- staticmethod 稱爲靜態方法類似於全局函數,不需要實例化也能調用。
75.Python 中的接口如何實現?
在類中提前設置好方法,利用 NotImplementedError
錯誤,當子類沒有覆寫方法的時候進行報錯。也可使用 @abstractmethod
對需要覆寫的方法進行裝飾,任何沒有覆寫該方法的子類都會報錯。
76.Python 中的反射了解麼?
反射是用於在類中尋找值的一種方式,有以下幾種用法:
- hasattr(class, key):在實例中尋找是否存在key名的函數或是變量返回布爾值。
- getattr(class, key, tips):獲得實例中變量或是方法的內存地址,可傳入第三個參數修改報錯提示。
- setattr(class, name, function):將函數以 name 爲名字傳入類中,通過 class.name(class) 的方式進行調用,setattr(class, name, value) 傳入變量及變量值,以 class.name 的形式調用。
- delattr(class, name):刪除類中變量,不能刪除函數。
77.metaclass 作用?以及應用場景?
metaclass 就是元類,元類是用來創建類的,也就是類的類
詳細瞭解:點此跳轉
78.hasattr() getattr() setattr()的用法
- hasattr(object,name):查詢類中是否存在符合關鍵字的函數或者方法,返回布爾值。
- getattr(object, name, [default]):查詢函數是否存在指定名字的變量或是方法,返回變量的值或者函數內存地址,若不存在報錯或是返回 default 中的自定義內容。
79.請列舉你知道的 Python 的魔法方法及用途。
__init__()
構造函數:
初始化數據並快速創建對象
默認隱藏無參數,只能有一個構造函數
無返回值,只能創建對象時調用__del__()
析構函數:對象死亡前調用 一般用於存儲數據__str__
:返回字符串,強調可讀性__repr__
:返回字符串,強調準確性__str__與__repr__
:
都返回字符串,前者面向用戶,後者面向程序員
如果兩者同時存在,str會覆蓋repr,優先執行__new__()
:可產生一個 “cls” 對應的實例,一定要有返回__eq__()
:判斷是否相等__doc__
:類的文檔/多行註釋__bases__
:獲得基類信息,結果爲元組__dict__
:獲得對象屬性的字典鍵值信息__class__
:獲得對象的類__name__
:獲得執行文件名字__file__
:獲得文件路徑
80.如何知道一個 Python 對象的類型?
使用 type() 函數
81.Python 的傳參是傳值還是傳址?
- 不可變參數用值傳遞,通過拷貝進行傳遞的
- 可變參數是引用傳遞的
82.Python 中的元類(metaclass)使用舉例
…
83.簡述 any() 和 all() 方法
any(object) 與 all(object) 區別:
- any 主要判斷對象中是否全爲空值(0、’’、None、Flase);若對象內全部爲空值則返回 False,否則返回 True
- all 則是判斷對象中是否存在空值;只要存在任一個空值則返回 False,否則返回 True
84.filter 方法求出列表所有奇數並構造新列表,a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
list(filter(lambda x:x if x%2 == 1 else None, a))
85.什麼是猴子補丁?
在運行代碼的過程中,對某個方法或者屬性進行替換的行爲稱爲猴子補丁。例如某個模塊中有一個查詢方法,開發中查詢數據庫中某個數據。在測試的過程中,不想查詢該數據庫了,則在測試代碼中覆蓋這個方法,這種行爲稱爲猴子補丁。
具體內容可以參考:猴子補丁相關知識點
86.在 Python 中是如何管理內存的?
參考71題的垃圾回收方式,Python 主要靠引用計數、垃圾回收、內存池管理進行內存管理。
其中內存池較爲複雜,這裏給出博客鏈接,供大家參考:內存池圖文解釋。這篇博客講的比較深,另外從內存池的設計方向展示了內存池的作用與設計原理,可以收藏了慢慢看。
87.當退出 Python 時是否釋放所有內存分配?
具有對象循環引用或者全局命名空間引用的變量退出時會被釋放
另外不會釋放 C 庫保留的部分內容
正則表達式
88.
(1) 使用正則表達式匹配出 <html><h1>百度一下,你就知道</html>
中的地址
pattern = "<html><h1>(.*?) </html>"
ma = pattern.match(<html><h1>www.baidu.com</html>)
print(ma.group(1))
(2) a=“張明 98 分”
,用 re.sub,將 98 替換爲 100。
re.sub('98', '100', a)
89.正則表達式匹配中 (.*)
和 (.*?)
匹配區別?
.*
單個字符匹配任意次,即貪婪匹配.*?
滿足條件的情況只匹配一次,即最小匹配
90.寫一段匹配郵箱的正則表達式
\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}
其他內容
91.解釋一下 Python 中 pass 語句的作用?
- 空語句,什麼也不做,表示佔位
- 在特別的時候用來保證格式或是語義的完整性
92.簡述你對 input()函數的理解
在 Python3 中,input() 函數接受一個標準輸入數據,返回爲 string 類型。不管我們輸入的回答是什麼,不管你輸入的是整數,還是字符串,input() 函數的輸入值(蒐集到的回答),永遠會被【強制性】地轉換爲【字符串】類型。(Python3 固定規則)
93.Python 中的 is 和 ==
- == :判斷 值,比較兩個對象是否相等
- is :判斷 地址,比較兩個引用是否指向了同一個對象(引用比較)
94.Python 中的作用域
作用域指的是函數名或者變量名的尋找順序,
優先級從高到低分別爲:局部作用域(子函數)>> 閉包函數外的函數中(父函數)>> 全局作用域(當前Python模塊)>> 內建作用域(Python標準庫)
95.三元運算寫法和應用場景?
形如 a= 'a' if b>1 else 'b'
,想用都能用,我個人感覺沒有什麼特定場景,屬於一種偷懶寫法。
96.瞭解 enumerate 麼?
內置函數,用來枚舉迭代器,返回結果爲 (index, value),可以方便的獲得迭代器的下標和值,也可以接受第三個參數,用於修改起始下標,
for index, value in enumerate(list, 1):
print(index, value)
則開始的下標從1開始。
97.列舉 5 個 Python 中的標準模塊
- os:與操作系統相關聯的函數,path 的 join()、split()、exists();mkdir()、listdir()、rename()、system() 等
- sys:通常用於命令行參數
- re:正則匹配,match、search、findall、sub、split、complie 等
- math:數學運算,三角函數(sin, cos, tan…)、向上向下取整(ceil, floor)、開方(sqrt) 等
- random:隨機模塊,random、randint、randrange 等
- calendar:日曆模塊
- time:時間模塊,時間戳
time.time
、線程休眠time.sleep()
等 - datetime:處理日期時間
98.如何在函數中設置一個全局變量
使用 global 關鍵字,例如 global a; a=a+1
這樣即可在函數中修改全局變量 a 的值。
99.pathlib 的用法舉例
這個庫是用來消除 windows 系統和 Linux 系統路徑分隔符不同的問題,實際使用過程中個人感覺意義不大,有興趣的可以看 官方文檔 瞭解一下。
100.Python 中的異常處理,寫一個簡單的應用場景
對文件的讀寫經常因爲編碼問題報錯,這裏使用 try …except的方法進行一個簡單處理:
try:
open('filename', 'r') as f:
f.readlines()
except:
print('error')
finally:
f.close()
101.Python 中遞歸的最大次數,那如何突破呢?
默認最大遞歸次數爲1000,通過以下代碼進行修改:
import sys
sys.setrecursionlimit(10000) # set the maximum depth as 10000
根據系統不同還存在解釋器上限,windows 下最大迭代次數約 4400次,linux 下最大迭代次數約爲24900次
102.什麼是面向對象的 mro
MRO(Method Resolution Order):方法解析順序。指對象在繼承或多次繼承後,方法的解析順序。詳細的解析可以 看這裏
103.isinstance 作用以及應用場景?
用於判斷對象是否與已知對象類型一致,功能上類似 type() 函數,type 不能分別是否繼承,isinstance 可以,具體解析 參考這裏
104.什麼是斷言?應用場景?
斷言也是一種異常處理的方式,可以判斷關鍵字後方的表達式是否爲真,若爲真則繼續執行,若爲假則拋出異常。
常用於一些數據的檢驗。具體應用場景 參考這裏
105.lambda 表達式格式以及應用場景?
labmda 又被稱爲匿名函數,用於一些簡單的函數處理,例如:lambda x:x^2
,這裏將傳入的 x 平方後返回,常常和循環結合在一起使用。
106.新式類和舊式類的區別
寫法上不同,多重繼承的屬性搜索算法改變了,具體可以 參考這裏
107.dir()是幹什麼用的?
顯示對象的屬性和方法。
108.一個包裏有三個模塊,demo1.py, demo2.py, demo3.py,但使用 from tools import *
導入模塊時,如何保證只有 demo1、demo3 被導入了。
from tools import demo1, demo3
109.列舉 5 個 Python 中的異常類型以及其含義
110.copy 和 deepcopy 的區別是什麼?
深拷貝:
- 將原對象的“ 值/元素 ”賦給新對象,新對象中元素的地址與原對象的 地址不同
- 是對原對象 所有層次 的拷貝(遞歸)
- 與原對象沒有任何關係,如果原對象發生變化,深拷貝後的新對象 不會發生改變
淺拷貝:
- 將原對象的 引用 賦給新對象,新對象中元素的地址與原對象的 地址相同
- 是對原對象 頂層 的拷貝(表面一層)
- 由於只拷貝了表面一層,當原對象中的嵌套對象發生改變時,新對象也 會發生改變
111.代碼中經常遇到的 *args, **kwargs
含義及用法。
- *args:元組參數,參數格式化存儲在一個元組中,長度沒有限制,必須位於普通參數和默認參數之後。
- **kwargs:字典參數,參數格式化存儲在一個字典中,必須位於參數列表的最後面。
112.Python 中會有函數或成員變量包含單下劃線前綴和結尾,和雙下劃線前綴結尾,區別是什麼?
單下劃線前綴表示是私有變量或函數,按照約定不能直接調用,雙下劃線前綴代表類的私有方法,只有類自身可以訪問,子類也不行。雙下劃線前綴結尾代表特殊方法,除了 Python 規定的函數以外,儘量不要使用。
113.w、a+、wb 文件寫入模式的區別
- r : 讀取文件,若文件不存在則會報錯
- w: 寫入文件,若文件不存在則會先創建再寫入,會覆蓋原文件
- a : 寫入文件,若文件不存在則會先創建再寫入,但不會覆蓋原文件,而是追加在文件末尾
- rb,wb:分別於 r, w 類似,但是用於讀寫二進制文件
- r+ : 可讀、可寫,文件不存在也會報錯,寫操作時會覆蓋
- w+ : 可讀,可寫,文件不存在先創建,會覆蓋
- a+ :可讀、可寫,文件不存在先創建,不會覆蓋,追加在末尾
114.舉例 sort 和 sorted 的區別
- sort 是應用在 list 上的方法,sorted 可以對 所有可迭代的對象 進行排序操作。
- list 的 sort 方法返回的是 對已經存在的列表進行操作,而內建函數 sorted 方法 返回的是一個新的 list,而不是在原來的基礎上進行的操作。
115.什麼是負索引?
Python 中的序列索引可以是正也可以是負。如果是正索引,0是序列中的第一個索引,1是第二個索引。如果是負索引,(-1)是最後一個索引而(-2)是倒數第二個索引。
116.pprint 模塊是幹什麼的?
提供了打印出任何Python數據結構類和方法
詳細瞭解請參考:點此跳轉
117.解釋一下 Python 中的賦值運算符
等號左邊爲變量名,右邊爲值,將右邊的值賦給左邊的變量。右邊如果是表達式,會將結果賦予左邊的變量。賦值運算符有(=,+=,-=,//=,%=,*=,/=)。具體看這裏
118.解釋一下 Python 中的邏輯運算符
- and:和
- or:或
- not:非
119.講講 Python 中的位運算符
- &:1 1爲1,其他爲0
- |:0 0爲0,其他爲1
- ~:按位取反,看符號位,求補碼,加一
- ^:相等爲0,不等爲1
>>
:右移位,數值變小<<
:左移位,數值變大
120.在 Python 中如何使用多進制數字?
在數字前添加前綴,0b 或 0B 前綴表示二進制數,前綴 0o 或 0O 表示8進制數,前綴 0x 或者 0X 表示16進制數。
121.怎樣聲明多個變量並賦值?
a, b = 1, 2
算法和數據結構
122.已知:
AList = [1, 2, 3]
BSet = {1, 2, 3}
(1) 從 AList 和 BSet 中 查找 4,最壞時間複雜度那個大?
(2) 從 AList 和 BSet 中 插入 4,最壞時間複雜度那個大?
123.用 Python 實現一個二分查找的函數
124.Python 單例模式的實現方法
參考這篇文章:點此跳轉
125.使用 Python 實現一個斐波那契數列
def fun(n):
a, b = 0, 1
while n>0:
yield b
a, b = b, a+b
n -= 1
詳細瞭解可查看這篇文章:點此跳轉
126.找出列表中的重複數字
準備一個空列表,循環目標列表裏的元素,不重複的丟進新列表裏,查到重複的就把下標和值打印出來。
127.找出列表中的單個數字
遍歷列表,找到相等的輸出下標和值。
128.寫一個冒泡排序
listA = [3,7,2,9,8,5]
for i in range(len(listA)-1): # 0 1 2 3 4
for j in range(len(listA)-1-i):
if listA[j] > listA[j+1]:
listA[j],listA[j+1] = listA[j+1],listA[j]
print(listA)
運行結果爲:
[2, 3, 5, 7, 8, 9]
129.寫一個快速排序
listA = [4, 3, 9, 6, 5, 8]
for i in range(len(listA) - 1): # 0 1 2 3 4
# 選擇一個值!!!
x = i
for j in range(i + 1, len(listA)):
if listA[x] > listA[j]:
x = j
listA[i], listA[x] = listA[x], listA[i]
print(listA)
print("結果!", listA)
運行結果爲:
結果: [3, 4, 5, 6, 8, 9]
130.寫一個拓撲排序
from collections import defaultdict
class Graph:
def __init__(self,vertices):
self.graph = defaultdict(list)
self.V = vertices
def addEdge(self,u,v):
self.graph[u].append(v)
def topologicalSortUtil(self,v,visited,stack):
visited[v] = True
for i in self.graph[v]:
if visited[i] == False:
self.topologicalSortUtil(i,visited,stack)
stack.insert(0,v)
def topologicalSort(self):
visited = [False]*self.V
stack =[]
for i in range(self.V):
if visited[i] == False:
self.topologicalSortUtil(i,visited,stack)
print (stack)
g= Graph(6)
g.addEdge(5, 2);
g.addEdge(5, 0);
g.addEdge(4, 0);
g.addEdge(4, 1);
g.addEdge(2, 3);
g.addEdge(3, 1);
print ("拓撲排序結果:")
g.topologicalSort()
運行結果爲:
拓撲排序結果:
[5, 4, 2, 3, 1, 0]
詳細瞭解:點此跳轉
131.Python 實現一個二進制計算
132.有一組“+”和“-”符號,要求將“+”排到左邊,“-”排到右邊,寫出具體的實現方法。
133.單鏈表反轉
134.交叉鏈表求交點
135.用隊列實現棧
136.找出數據流的中位數
137.二叉搜索樹中第 K 小的元素
爬蟲相關
138.在 requests 模塊中,requests.content 和 requests.text 什麼區別
requests.content 是二進制字符串,requests.text 返回的是普通字符串。
139.簡要寫一下 lxml 模塊的使用方法框架
使用 etree 對 html 文件進行解析,獲取對應的 tag 和屬性。
140.說一說 scrapy 的工作流程
-
首先 Spiders(爬蟲)將需要發送請求的 url(requests) 經 ScrapyEngine(引擎)交給 Scheduler(調度器)。
-
Scheduler(排序,入隊)處理後,經 ScrapyEngine,DownloaderMiddlewares (可選,主要有User_Agent, Proxy代理) 交給 Downloader。
-
Downloader 向互聯網發送請求,並接收下載響應(response)。將響應(response)經ScrapyEngine,SpiderMiddlewares (可選)交給 Spiders。
-
Spiders 處理 response,提取數據並將數據經 ScrapyEngine 交給 ItemPipeline 保存(可以是本地,可以是數據庫)。
-
提取 url 重新經 ScrapyEngine 交給 Scheduler 進行下一個循環。直到無 Url 請求程序停止結束。
141.scrapy 的去重原理
- scrapy 本身自帶有一箇中間件;
- scrapy 源碼中可以找到一個 dupefilters.py 去重器;
- 需要將 dont_filter 設置爲 False 開啓去重,默認是 False 去重,改爲 True, 就是沒有開啓去重;
- 對於每一個 url 的請求,調度器都會根據請求得相關信息加密得到一個指紋信息,並且將指紋信息和 set() 集合中的指紋信息進行比對,如果 set() 集合中已經存在這個數據,就不在將這個 Request 放入隊列中;
- 如果 set() 集合中沒有存在這個加密後的數據,就將這個 Request 對象放入隊列中,等待被調度。
142.scrapy 中間件有幾種類,你用過哪些中間件
scrapy 的中間件理論上有三種 (Schduler Middleware, Spider Middleware, Downloader Middleware), 在應用上一般有以下兩種:
-
爬蟲中間件 Spider Middleware
主要功能是在爬蟲運行過程中進行一些處理 -
下載器中間件 Downloader Middleware
主要功能在請求到網頁後,頁面被下載時進行一些處理
143.你寫爬蟲的時候都遇到過什麼?反爬蟲措施,你是怎麼解決的?
限制訪問次數,檢驗瀏覽器頭,異步加載,驗證碼,限制 IP 。
限制訪問速度的加延時,瀏覽器頭加 headers 參數,異步加載抓包找訪問地址,驗證碼接打碼平臺或者用自動化框架過,IP 用代理。
144.爲什麼會用到代理?
很多網站限制 IP 訪問的速度和次數,導致大規模採集的時候影響速度,也可能因爲多次訪問被封禁 IP,所以用代理的方式繞過。
145.代理失效了怎麼處理?
一般嘗試三次,失敗了重新丟回隊列中,換個代理地址繼續用。
146.列出你知道 header 的內容以及信息
- user-agent:瀏覽器頭信息
- refer:表示從哪個網頁跳轉的
147.說一說打開瀏覽器訪問 百度一下,你就知道 獲取到結果,整個流程。
先向 DNS 服務器查詢對應 IP ,瀏覽器訪問 IP ,網站響應若是 HTTPS 的驗證一下證書,然後 TCP 三次握手開始傳數據。
148.爬取速度過快出現了驗證碼怎麼處理
- 設置延時
- 使用打碼平臺
- 嘗試登錄後爬取
- 掛代理多 IP 爬。
149.scrapy 和 scrapy-redis 有什麼區別?爲什麼選擇 redis 數據庫?
-
scrapy 是一個 python爬蟲框架,爬取效率極高,具有高度定製性,但是不支持分佈式;
而 scrapy-redis 是一套基於 redis 數據庫、運行在 scrapy 框架之上的組件,可以讓 scrapy 支持分佈式策略,Slaver 端共享 Master 端 redis 數據庫裏的 item 隊列、請求隊列和請求指紋集合。 -
爲什麼選擇 redis 數據庫,因爲 redis 支持主從同步,而且數據都是緩存在內存中的,所以基於 redis 的分佈式爬蟲,對請求和數據的高頻讀取效率非常高。
150.分佈式爬蟲主要解決什麼問題
- IP
- 帶寬
- CPU
- IO
151.寫爬蟲是用多進程好?還是多線程好? 爲什麼?
限制爬蟲的兩方面,一個是網絡請求速度,這個通過線程來提升。另一個是硬盤讀寫,這個用多進程解決。
IO 密集型代碼(文件處理、網絡爬蟲等),多線程能夠有效提升效率(單線程下有 IO 操作會進行 IO 等待,造成不必要的時間浪費,而開啓多線程能在線程A等待時,自動切換到線程B,可以不浪費 CPU 的資源,從而能提升程序執行效率)。在實際的數據採集過程中,既考慮網速和響應的問題,也需要考慮自身機器的硬件情況,來設置多進程或多線程
152.解析網頁的解析器使用最多的是哪幾個
- BeautifulSoup4
- xpath (lxml 庫)
- 正則表達式
153.需要登錄的網頁,如何解決同時限制 ip, cookie, session(其中有一些是動態生成的)在不使用動態爬取的情況下?
自動化框架
154.驗證碼的解決(簡單的:對圖像做處理後可以得到的,困難的:驗證碼是點擊,拖動等動態進行的?)
簡單的圖像識別,困難的自動化框架,再不行接打碼平臺。
155.使用最多的數據庫(mysql,mongodb,redis 等),對他的理解?
參考這篇文章:點此跳轉
網絡編程
156.TCP 和 UDP 的區別?
-
連接方面區別
TCP 面向連接(如打電話要先撥號建立連接)。
UDP 是無連接的,即發送數據之前不需要建立連接。 -
安全方面的區別
TCP 提供可靠的服務,通過 TCP 連接傳送的數據,無差錯,不丟失,不重複,且按序到達。
UDP 盡最大努力交付,即不保證可靠交付。 -
傳輸效率的區別
TCP 傳輸效率相對較低。
UDP 傳輸效率高,適用於對高速傳輸和實時性有較高的通信或廣播通信。 -
連接對象數量的區別
TCP 連接只能是點到點、一對一的。
UDP 支持一對一,一對多,多對一和多對多的交互通信。
157.簡要介紹三次握手和四次揮手
參考這篇文章:點此跳轉
158.什麼是粘包? socket 中造成粘包的原因是什麼? 哪些情況會發生粘包現象?
併發
159.舉例說明 conccurent.future 的中線程池的用法
160.說一說多線程,多進程和協程的區別。
參考這篇文章:點此跳轉
161.簡述 GIL
技術進步,CPU從原來的單核變爲了多核,爲了防止程序在多線程操作的時候同時執行,加了一個GIL鎖,保證在同一時刻只能有一個線程在運行程序。
參考這篇文章:點此跳轉
162.進程之間如何通信
一種是採用隊列 Queue 的方式,多用於多進程通信。通過 put 和 get 方法向隊列中放入值和取出值實現通信。Pipe 常於兩個進程間通信,利用 send 和 recv 發送和接收變量。
參考這篇文章:點此跳轉
163.IO 多路複用的作用?
節約資源,一個進程監聽多個文件的狀態,利用輪詢代替一對一監控。
參考這篇文章:點此跳轉
164.select、poll、epoll 模型的區別?
- select 利用系統自身調度系統,生成一個數組,將監控的文件描述符都放進去,進行遍歷監控,文件就緒時傳遞給程序進行處理。
- poll 和 select 類似,但由於select 類型是數組,存在上限,而 poll 使用鏈表,沒有上限,同時效率比起 select 更高。
- epoll 改進了前兩種方式,利用回調函數的方法,將就緒的文件描述符添加進一個數組中,只對這個數組進行遍歷。
參考這篇文章:點此跳轉
165.什麼是併發和並行?
- 併發就是多個線程輪流執行
- 並行就是多個線程同時執行。
166.一個線程 1 讓線程 2 去調用一個函數怎麼實現?
167.解釋什麼是異步非阻塞?
發送方發送數據後不等回覆就繼續做自己的事,接收方接到數據後一邊進行數據處理一邊做自己的事,處理結束後將結果傳回給發送方。這樣的方式稱爲異步非阻塞,同理有同步阻塞/非阻塞,異步阻塞/非阻塞。
參考這篇文章:點此跳轉
168.threading.local 的作用
用於保存一個全局變量,這個變量只能在當前的線程中進行訪問。
Git 面試題
169.說說你知道的 git 命令
-
初始化
git init
-
添加到暫存盤
git add .
-
提交
git commit -m "提示信息"
-
查看信息
git log
-
查看相關歷史信息
git reflog
-
測試工作區操作
git checkout --文件名
-
回退版本
git reset --hard 版本id
-
查看分支
git branch
-
創建分支
git branch <name>
-
切換分支
git checkout <name>
-
創建+切換分支
git checkout -b <name>
-
合併某分支到當前分支
git merge <name>
-
刪除分支
git branch -d <name>
-
添加遠程倉庫
git remote add origin [email protected]:xxx/xxx.git
-
推送本地代碼到遠程
git push -u origin master -f
170.git 如何查看某次提交修改的內容
- 首先,需要通過
git log
打印所有 commit 記錄 - 找到你想查看的哪次 commit 的 commitid。
- 查看修改:
git show commitId
- 查看某次 commit 中具體某個文件的修改:
git show commitId fileName