Python 常見180道面試題解析(更新中...)


基礎

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 的一種編碼規範,具體如下:

  1. 縮進。4個空格的縮進(編輯器都可以完成此功能),不使用 tab,更不能混合使用 tab 和空格。
  2. 每行最大長度79,換行可以使用反斜槓,最好使用圓括號。換行點要在操作符的後邊敲回車。
  3. 類和 top-level 函數定義之間空兩行;類中的方法定義之間空一行;函數內邏輯無關段落之間空一行;其他地方儘量不要再空行。
  4. 模塊導入的順序:按標準、三方和自己編寫順序依次導入,之間空一行。
  5. 不要在一句 import 中多個庫,比如 import os, sys 不推薦
  6. 避免不必要的空格
  7. 註釋必須要有
  8. 函數命名要遵循規範
  9. 儘可能使用 ‘is’ ‘is not’ 取代 ‘==’,比如 if x is not None 要優於 if x
  10. 使用基於類的異常,每個模塊或包都有自己的異常類,此異常類繼承自 Exception。
  11. 異常中 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.瞭解分佈式鎖麼?

多進程併發執行任務時,需要保證任務的有序性或者唯一性,所以就要用到分佈式鎖

  1. 同一時刻只能存在一個鎖
  2. 需要解決意外死鎖問題,也就是鎖能超時自動釋放
  3. 支持主動釋放鎖

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 語句的作用?

  1. 空語句,什麼也不做,表示佔位
  2. 在特別的時候用來保證格式或是語義的完整性

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 的工作流程

  1. 首先 Spiders(爬蟲)將需要發送請求的 url(requests) 經 ScrapyEngine(引擎)交給 Scheduler(調度器)。

  2. Scheduler(排序,入隊)處理後,經 ScrapyEngine,DownloaderMiddlewares (可選,主要有User_Agent, Proxy代理) 交給 Downloader。

  3. Downloader 向互聯網發送請求,並接收下載響應(response)。將響應(response)經ScrapyEngine,SpiderMiddlewares (可選)交給 Spiders。

  4. Spiders 處理 response,提取數據並將數據經 ScrapyEngine 交給 ItemPipeline 保存(可以是本地,可以是數據庫)。

  5. 提取 url 重新經 ScrapyEngine 交給 Scheduler 進行下一個循環。直到無 Url 請求程序停止結束。

scrapy流程圖

141.scrapy 的去重原理

  1. scrapy 本身自帶有一箇中間件;
  2. scrapy 源碼中可以找到一個 dupefilters.py 去重器;
  3. 需要將 dont_filter 設置爲 False 開啓去重,默認是 False 去重,改爲 True, 就是沒有開啓去重;
  4. 對於每一個 url 的請求,調度器都會根據請求得相關信息加密得到一個指紋信息,並且將指紋信息和 set() 集合中的指紋信息進行比對,如果 set() 集合中已經存在這個數據,就不在將這個 Request 放入隊列中;
  5. 如果 set() 集合中沒有存在這個加密後的數據,就將這個 Request 對象放入隊列中,等待被調度。

142.scrapy 中間件有幾種類,你用過哪些中間件

scrapy 的中間件理論上有三種 (Schduler Middleware, Spider Middleware, Downloader Middleware), 在應用上一般有以下兩種:

  1. 爬蟲中間件 Spider Middleware
    主要功能是在爬蟲運行過程中進行一些處理

  2. 下載器中間件 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 的區別?

  1. 連接方面區別
    TCP 面向連接(如打電話要先撥號建立連接)。
    UDP 是無連接的,即發送數據之前不需要建立連接。

  2. 安全方面的區別
    TCP 提供可靠的服務,通過 TCP 連接傳送的數據,無差錯,不丟失,不重複,且按序到達。
    UDP 盡最大努力交付,即不保證可靠交付。

  3. 傳輸效率的區別
    TCP 傳輸效率相對較低。
    UDP 傳輸效率高,適用於對高速傳輸和實時性有較高的通信或廣播通信。

  4. 連接對象數量的區別
    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 如何查看某次提交修改的內容

  1. 首先,需要通過 git log 打印所有 commit 記錄
  2. 找到你想查看的哪次 commit 的 commitid。
  3. 查看修改:git show commitId
  4. 查看某次 commit 中具體某個文件的修改:git show commitId fileName
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章