萬字長文Python面試題,建議先收藏

精心整理的 Python 相關(guān)的基礎(chǔ)知識,用于面試,或者平時復(fù)習(xí),都是很好的!廢話不多說,直接開搞 由于文章過長,蘿卜哥也貼心的把文章整理成了PDF文檔,在文末查看獲取方式 [TOC] ## 基礎(chǔ)篇 ### 1. 為什么學(xué)習(xí) Python Python 語言簡單易懂,上手容易,隨著 AI 風(fēng)潮,越來越火 ### 2. 解釋型和編譯型語言的區(qū)別 編譯型語言:把做好的源程序全部編譯成二進(jìn)制的可運(yùn)行程序。然后,可直接運(yùn)行這個程序。如:C,C++ 解釋型語言:把做好的源程序翻譯一句,然后執(zhí)行一句,直至結(jié)束!如:Python, (Java 有些特殊,java程序也需要編譯,但是沒有直接編譯稱為機(jī)器語言,而是編譯稱為字節(jié)碼,然后用解釋方式執(zhí)行字節(jié)碼。) ### 3. 簡述下 Python 中的字符串、列表、元組和字典 字符串(str):字符串是用引號括起來的任意文本,是編程語言中最常用的數(shù)據(jù)類型 列表(list):列表是有序的集合,可以向其中添加或刪除元素 元組(tuple):元組也是有序集合,但是是無法修改的。即元組是不可變的 字典(dict):字典是無序的集合,是由 key-value 組成的 集合(set):是一組 key 的集合,每個元素都是唯一,不重復(fù)且無序的 ### 4. 簡述上述數(shù)據(jù)類型的常用方法 字符串: 1. 切片 ```Python mystr='luobodazahui' mystr[1:3] ``` output ```Text 'uo' ``` 2. format ```Python mystr2 = "welcome to luobodazahui, dear {name}" mystr2.format(name="baby") ``` output ```Text 'welcome to luobodazahui, dear baby' ``` 3. join 可以用來連接字符串,將字符串、元組、列表中的元素以指定的字符(分隔符)連接生成一個新的字符串 ```Python mylist = ['luo', 'bo', 'da', 'za', 'hui'] mystr3 = '-'.join(mylist) print(mystr3) ``` outout ```Text 'luo-bo-da-za-hui' ``` 4. replace String.replace(old,new,count) 將字符串中的 old 字符替換為 New 字符,count 為替換的個數(shù) ```Python mystr4 = 'luobodazahui-haha' print(mystr4.replace('haha', 'good')) ``` output ```Text luobodazahui-good ``` 5. split 切割字符串,得到一個列表 ```Python mystr5 = 'luobo,dazahui good' # 以空格分割 print(mystr5.split()) # 以h分割 print(mystr5.split('h')) # 以逗號分割 print(mystr5.split(',')) ``` output ```Text ['luobo,dazahui', 'good'] ['luobo,daza', 'ui good'] ['luobo', 'dazahui good'] ``` 列表: 1. 切片 同字符串 2. append 和 extend 向列表中國添加元素 ```Python mylist1 = [1, 2] mylist2 = [3, 4] mylist3 = [1, 2] mylist1.append(mylist2) print(mylist1) mylist3.extend(mylist2) print(mylist3) ``` outout ```Text [1, 2, [3, 4]] [1, 2, 3, 4] ``` 3. 刪除元素 del:根據(jù)下標(biāo)進(jìn)行刪除 pop:刪除最后一個元素 remove:根據(jù)元素的值進(jìn)行刪除 ```Python mylist4 = ['a', 'b', 'c', 'd'] del mylist4[0] print(mylist4) mylist4.pop() print(mylist4) mylist4.remove('c') print(mylist4) ``` output ```Text ['b', 'c', 'd'] ['b', 'c'] ['b'] ``` 4. 元素排序 sort:是將list按特定順序重新排列,默認(rèn)為由小到大,參數(shù) reverse=True 可改為倒序,由大到小。 reverse:是將list逆置 ```Python mylist5 = [1, 5, 2, 3, 4] mylist5.sort() print(mylist5) mylist5.reverse() print(mylist5) ``` output ```Text [1, 2, 3, 4, 5] [5, 4, 3, 2, 1] ``` 字典: 1. 清空字典 dict.clear() ```Python dict1 = {'key1':1, 'key2':2} dict1.clear() print(dict1) ``` output ```Text {} ``` 2. 指定刪除 使用 pop 方法來指定刪除字典中的某一項(xiàng) ```Python dict1 = {'key1':1, 'key2':2} d1 = dict1.pop('key1') print(d1) print(dict1) ``` output ```Text 1 {'key2': 2} ``` 3. 遍歷字典 ```Python dict2 = {'key1':1, 'key2':2} mykey = [key for key in dict2] print(mykey) myvalue = [value for value in dict2.values()] print(myvalue) key_value = [(k, v) for k, v in dict2.items() ] print(key_value) ``` output ```Text ['key1', 'key2'] [1, 2] [('key1', 1), ('key2', 2)] ``` 4. fromkeys 用于創(chuàng)建一個新字典,以序列中元素做字典的鍵,value 為字典所有鍵對應(yīng)的初始值 ```Python keys = ['zhangfei', 'guanyu', 'liubei', 'zhaoyun'] dict.fromkeys(keys, 0) ``` output ```Text {'zhangfei': 0, 'guanyu': 0, 'liubei': 0, 'zhaoyun': 0} ``` ### 5. 簡述 Python 中的字符串編碼 計(jì)算機(jī)在最初的設(shè)計(jì)中,采用了8個比特(bit)作為一個字節(jié)(byte)的方式。一個字節(jié)能表示的最大的整數(shù)就是255(二進(jìn)制11111111=十進(jìn)制255),如果要表示更大的整數(shù),就必須用更多的字節(jié) 最早,計(jì)算機(jī)只有 ASCII 編碼,即只包含大小寫英文字母、數(shù)字和一些符號,這些對于其他語言,如中文,日文顯然是不夠用的。后來又發(fā)明了Unicode,Unicode把所有語言都統(tǒng)一到一套編碼里,這樣就不會再有亂碼問題了。當(dāng)需要保存到硬盤或者需要傳輸?shù)臅r候,就轉(zhuǎn)換為UTF-8編碼。UTF-8 是隸屬于 Unicode 的可變長的編碼方式 在 Python 中,以 Unicode 方式編碼的字符串,可以使用 encode() 方法來編碼成指定的 bytes,也可以通過 decode() 方法來把 bytes 編碼成字符串 encode ```Python "中文".encode('utf-8') ``` output ```Text b'\xe4\xb8\xad\xe6\x96\x87' ``` decode ```Python b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8') ``` output ```Text '中文' ``` ### 6.一行代碼實(shí)現(xiàn)數(shù)值交換 ```Python 1a = 1 2b = 2 3a, b = b, a 4print(a, b) ``` output ```Text 12 1 ``` ### 7. is 和 == 的區(qū)別 先來看個例子 ```Python c = d = [1,2] e = [1,2] print(c is d) print(c == d) print(c is e) print(c == e) ``` output ```Text True True False True ``` == 是比較操作符,只是判斷對象的值(value)是否一致,而 is 則判斷的是對象之間的身份(內(nèi)存地址)是否一致。對象的身份,可以通過 id() 方法來查看 ```Python id(c) id(d) id(e) ``` output ```Text 88748080 88748080 88558288 ``` 可以看出,只有 id 一致時,is 比較才會返回 True,而當(dāng) value 一致時,== 比較就會返回 True ### 8.Python 函數(shù)中的參數(shù)類型 位置參數(shù),默認(rèn)參數(shù),可變參數(shù),關(guān)鍵字參數(shù) ### 9.`*arg` 和 `**kwarg` 作用 允許我們在調(diào)用函數(shù)的時候傳入多個實(shí)參 ```Python def test(*arg, **kwarg): if arg: print("arg:", arg) if kwarg: print("kearg:", kwarg) test('ni', 'hao', key='world') ``` output ```Text arg: ('ni', 'hao') kearg: {'key': 'world'} ``` 可以看出, `*arg` 會把位置參數(shù)轉(zhuǎn)化為 tuple `**kwarg` 會把關(guān)鍵字參數(shù)轉(zhuǎn)化為 dict ### 10.一行代碼實(shí)現(xiàn)1-100之和 ```Python sum(range(1, 101)) ``` ### 11.獲取當(dāng)前時間 ```Python import time import datetime print(datetime.datetime.now()) print(time.strftime('%Y-%m-%d %H:%M:%S')) ``` output ```Text 2019-06-07 18:12:11.165330 2019-06-07 18:12:11 ``` ### 12.PEP8 規(guī)范 簡單列舉10條: - 盡量以免單獨(dú)使用小寫字母'l',大寫字母'O',以及大寫字母'I'等容易混淆的字母 - 函數(shù)命名使用全部小寫的方式,可以使用下劃線 - 常量命名使用全部大寫的方式,可以使用下劃線 - 使用 has 或 is 前綴命名布爾元素,如: is_connect = True; has_member = False - 不要在行尾加分號, 也不要用分號將兩條命令放在同一行 - 不要使用反斜杠連接行 - 頂級定義之間空2行, 方法定義之間空1行,頂級定義之間空兩行 - 如果一個類不繼承自其它類, 就顯式的從object繼承 - 內(nèi)部使用的類、方法或變量前,需加前綴`_`表明此為內(nèi)部使用的 - 要用斷言來實(shí)現(xiàn)靜態(tài)類型檢測 ### 13.Python 的深淺拷貝 淺拷貝 ```Python import copy list1 = [1, 2, 3, [1, 2]] list2 = copy.copy(list1) list2.append('a') list2[3].append('a') print(list1, list2) ``` output ```Text [1, 2, 3, [1, 2, 'a']] [1, 2, 3, [1, 2, 'a'], 'a'] ``` 能夠看出,淺拷貝只成功”獨(dú)立“拷貝了列表的外層,而列表的內(nèi)層列表,還是共享的 深拷貝 ```Python import copy list1 = [1, 2, 3, [1, 2]] list3 = copy.deepcopy(list1) list3.append('a') list3[3].append('a') print(list1, list3) ``` output ```Text [1, 2, 3, [1, 2]] [1, 2, 3, [1, 2, 'a'], 'a'] ``` 深拷貝使得兩個列表完全獨(dú)立開來,每一個列表的操作,都不會影響到另一個 ### 14.查看下面代碼的輸出 ```Python def num(): return [lambda x:i*x for i in range(4)] print([m(1) for m in num()]) ``` output ```Text [3, 3, 3, 3] ``` 通過運(yùn)行結(jié)果,可以看出 i 的取值為3,很神奇 ### 15.可變類型與不可變類型 可變數(shù)據(jù)類型:list、dict、set 不可變數(shù)據(jù)類型:int/float、str、tuple ### 16.打印九九乘法表 ```Python for i in range(1, 10): for j in range(1, i+1): print("%s*%s=%s " %(i, j, i*j), end="") print() ``` output ```Text 1*1=1 2*1=2 2*2=4 3*1=3 3*2=6 3*3=9 4*1=4 4*2=8 4*3=12 4*4=16 5*1=5 5*2=10 5*3=15 5*4=20 5*5=25 6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36 7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49 8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64 9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81 ``` print 函數(shù),默認(rèn)是會換行的,其有一個默認(rèn)參數(shù) end,如果像例子中,我們把 end 參數(shù)顯示的置為"",那么 print 函數(shù)執(zhí)行完后,就不會換行了,這樣就達(dá)到了九九乘法表的效果了 ### 17.filter、map、reduce 的作用 filter 函數(shù)用于過濾序列,它接收一個函數(shù)和一個序列,把函數(shù)作用在序列的每個元素上,然后根據(jù)返回值是True還是False決定保留還是丟棄該元素 ```Python mylist = [1, 2, 3, 4, 5, 6, 7, 8, 9] list(filter(lambda x: x%2 == 1, mylist)) ``` output ```Text [1, 3, 5, 7, 9] ``` 保留奇數(shù)列表 map 函數(shù)傳入一個函數(shù)和一個序列,并把函數(shù)作用到序列的每個元素上,返回一個可迭代對象 ```Python mylist = [1, 2, 3, 4, 5, 6, 7, 8, 9] list(map(lambda x: x*2, mylist)) ``` output ```Text [2, 4, 6, 8, 10, 12, 14, 16, 18] ``` reduce 函數(shù)用于遞歸計(jì)算,同樣需要傳入一個函數(shù)和一個序列,并把函數(shù)和序列元素的計(jì)算結(jié)果與下一個元素進(jìn)行計(jì)算 ```Python from functools import reduce reduce(lambda x, y: x+y, range(101)) ``` output ```Text 5050 ``` 可以看出,上面的三個函數(shù)與匿名函數(shù)相結(jié)合使用,可以寫出強(qiáng)大簡潔的代碼 ### 18.re 的 match 和 search 區(qū)別 match()函數(shù)只檢測要匹配的字符是不是在 string 的開始位置匹配,search()會掃描整個 string 查找匹配 ### 19.面向?qū)ο笾衊__new__` 和 `__init__` 區(qū)別 `__new__`是在實(shí)例創(chuàng)建之前被調(diào)用的,因?yàn)樗娜蝿?wù)就是創(chuàng)建實(shí)例然后返回該實(shí)例對象,是個靜態(tài)方法 `__init__`是當(dāng)實(shí)例對象創(chuàng)建完成后被調(diào)用的,然后設(shè)置對象屬性的一些初始值,通常用在初始化一個類實(shí)例的時候,是一個實(shí)例方法 1、`__new__`至少要有一個參數(shù) cls,代表當(dāng)前類,此參數(shù)在實(shí)例化時由 Python 解釋器自動識別 2、`__new__`必須要有返回值,返回實(shí)例化出來的實(shí)例,這點(diǎn)在自己實(shí)現(xiàn)`__new__`時要特別注意,可以 return 父類(通過 super(當(dāng)前類名, cls))`__new__`出來的實(shí)例,或者直接是 object 的`__new__`出來的實(shí)例 3、`__init__`有一個參數(shù) self,就是這個`__new__`返回的實(shí)例,`__init__`在`__new__`的基礎(chǔ)上可以完成一些其它初始化的動作,`__init__`不需要返回值 4、如果`__new__`創(chuàng)建的是當(dāng)前類的實(shí)例,會自動調(diào)用`__init__`函數(shù),通過 return 語句里面調(diào)用的`__new__`函數(shù)的第一個參數(shù)是 cls 來保證是當(dāng)前類實(shí)例,如果是其他類的類名,那么實(shí)際創(chuàng)建返回的就是其他類的實(shí)例,其實(shí)就不會調(diào)用當(dāng)前類的`__init__`函數(shù),也不會調(diào)用其他類的`__init__`函數(shù) ### 20.三元運(yùn)算規(guī)則 ```Python a, b = 1, 2 # 若果 a>b 成立 就輸出 a-b 否則 a+b h = a-b if a>b else a+b ``` output ```Text 3 ``` ### 21.生成隨機(jī)數(shù) ```Python print(random.random()) print(random.randint(1, 100)) print(random.uniform(1,5)) ``` output ```Text 0.03765019937131564 18 1.8458555362279228 ``` ### 22.zip 函數(shù)用法 zip() 函數(shù)將可迭代的對象作為參數(shù),將對象中對應(yīng)的元素打包成一個個元組,然后返回由這些元組組成的列表 ```Python list1 = ['zhangfei', 'guanyu', 'liubei', 'zhaoyun'] list2 = [0, 3, 2, 4] list(zip(list1, list2)) ``` output ```Text [('zhangfei', 0), ('guanyu', 3), ('liubei', 2), ('zhaoyun', 4)] ``` ### 23.range 和 xrange 的區(qū)別 range([start,] stop[, step]),根據(jù)start與stop指定的范圍以及step設(shè)定的步長,生成一個序列 而 xrange 生成一個生成器,可以很大的節(jié)約內(nèi)存 ### 24.with 方法打開文件的作用 開文件在進(jìn)行讀寫的時候可能會出現(xiàn)一些異常狀況,如果按照常規(guī)的 f.open 寫法,我們需要 try,except,finally,做異常判斷,并且文件最終不管遇到什么情況,都要執(zhí)行 finally f.close() 關(guān)閉文件,with 方法幫我們實(shí)現(xiàn)了 finally 中 f.close ### 25.什么是正則的貪婪匹配 Python 中默認(rèn)是貪婪匹配模式 貪婪模式:正則表達(dá)式一般趨向于最大長度匹配 非貪婪模式:在整個表達(dá)式匹配成功的前提下,盡可能少的匹配 ### 26.為什么不建議函數(shù)的默認(rèn)參數(shù)傳入可變對象 例如: ```Python def test(L=[]): L.append('test') print(L) ``` output ```Text test() # ['test'] test() # ['test', 'test'] ``` 默認(rèn)參數(shù)是一個列表,是可變對象[],Python 在函數(shù)定義的時候,默認(rèn)參數(shù) L 的值就被計(jì)算出來了,是[],每次調(diào)用函數(shù),如果 L 的值變了,那么下次調(diào)用時,默認(rèn)參數(shù)的值就已經(jīng)不再是[]了 ### 27.字符串轉(zhuǎn)列表 ```Python mystr = '1,2,3' mystr.split(',') ``` output ```Text ['1', '2', '3'] ``` ### 28.字符串轉(zhuǎn)整數(shù) ```Python mylist = ['1', '2', '3'] list(map(lambda x: int(x), mylist)) ``` output ```Text [1, 2, 3] ``` ### 29.刪除列表中的重復(fù)值 ```Python mylist = [1, 2, 3, 4, 5, 5] list(set(mylist)) ``` ### 30.字符串單詞統(tǒng)計(jì) ```Python from collections import Counter mystr = 'sdfsfsfsdfsd,were,hrhrgege.sdfwe!sfsdfs' Counter(mystr) output Counter({'s': 9, 'd': 5, 'f': 7, ',': 2, 'w': 2, 'e': 5, 'r': 3, 'h': 2, 'g': 2, '.': 1, '!': 1}) ``` ### 31.列表推導(dǎo),求奇偶數(shù) ```Python [x for x in range(10) if x%2 == 1] ``` output ```Text [1, 3, 5, 7, 9] ``` ### 32.一行代碼展開列表 ```Python list1 = [[1,2],[3,4],[5,6]] [j for i in list1 for j in i] ``` output ```Text [1, 2, 3, 4, 5, 6] ``` ### 33.實(shí)現(xiàn)二分法查找函數(shù) 二分查找算法也稱折半查找,基本思想就是折半,對比大小后再折半查找,必須是有序序列才可以使用二分查找 遞歸算法 ```Python def binary_search(data, item): # 遞歸 n = len(data) if n > 0: mid = n // 2 if data[mid] == item: return True elif data[mid] > item: return binary_search(data[:mid], item) else: return binary_search(data[mid+1:], item) return False list1 = [1,4,5,66,78,99,100,101,233,250,444,890] binary_search(list1, 999) ``` 非遞歸算法 ```Python def binary_search(data, item): # 非遞歸 n = len(data) first = 0 last = n - 1 while first <= last: mid = (first + last)//2 if data[mid] == item: return True elif data[mid] > item: last = mid - 1 else: first = mid + 1 return False list1 = [1,4,5,66,78,99,100,101,233,250,444,890] binary_search(list1, 99) ``` ### 34.字典和 json 轉(zhuǎn)換 字典轉(zhuǎn) json ```Python import json dict1 = {'zhangfei':1, "liubei":2, "guanyu": 4, "zhaoyun":3} myjson = json.dumps(dict1) myjson output '{"zhangfei": 1, "liubei": 2, "guanyu": 4, "zhaoyun": 3}' json 轉(zhuǎn)字典 mydict = json.loads(myjson) mydict ``` output ```Text {'zhangfei': 1, 'liubei': 2, 'guanyu': 4, 'zhaoyun': 3} ``` ### 35.列表推導(dǎo)式、字典推導(dǎo)式和生成器 ```Python import random td_list=[i for i in range(10)] print("列表推導(dǎo)式", td_list, type(td_list)) ge_list = (i for i in range(10)) print("生成器", ge_list) dic = {k:random.randint(4, 9)for k in ["a", "b", "c", "d"]} print("字典推導(dǎo)式",dic,type(dic)) ``` output ```Text 列表推導(dǎo)式 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 生成器 at 0x0139F070> 字典推導(dǎo)式 {'a': 6, 'b': 5, 'c': 8, 'd': 9} ``` ### 36.簡述 read、readline、readlines 的區(qū)別 read 讀取整個文件 readline 讀取下一行,使用生成器方法 readlines 讀取整個文件到一個迭代器以供我們遍歷 ### 37.打亂一個列表 ```Python list2 = [1, 2, 3, 4, 5, 6] random.shuffle(list2) print(list2) ``` output ```Text [4, 6, 5, 1, 2, 3] ``` ### 38.反轉(zhuǎn)字符串 ```Python str1 = 'luobodazahui' str1[::-1] ``` output ```Text 'iuhazadoboul' ``` ### 39.單下劃線和雙下劃線的作用 `__foo__`:一種約定,Python 內(nèi)部的名字,用來區(qū)別其他用戶自定義的命名,以防沖突,就是例如`__init__()`,`__del__()`,`__call__()`些特殊方法 `_foo`:一種約定,用來指定變量私有。不能用 from module import * 導(dǎo)入,其他方面和公有變量一樣訪問 `__foo`:這個有真正的意義:解析器用`_classname__foo` 來代替這個名字,以區(qū)別和其他類相同的命名,它無法直接像公有成員一樣隨便訪問,通過對象名`._`類名`__xxx` 這樣的方式可以訪問 ### 40.新式類和舊式類 a. 在 python 里凡是繼承了 object 的類,都是新式類 b. Python3 里只有新式類 c. Python2 里面繼承 object 的是新式類,沒有寫父類的是經(jīng)典類 d. 經(jīng)典類目前在 Python 里基本沒有應(yīng)用 ### 41.Python 面向?qū)ο笾械睦^承有什么特點(diǎn) a. 同時支持單繼承與多繼承,當(dāng)只有一個父類時為單繼承,當(dāng)存在多個父類時為多繼承 b. 子類會繼承父類所有的屬性和方法,子類也可以覆蓋父類同名的變量和方法 c. 在繼承中基類的構(gòu)造(`__init__()`)方法不會被自動調(diào)用,它需要在其派生類的構(gòu)造中專門調(diào)用 d. 在調(diào)用基類的方法時,需要加上基類的類名前綴,且需要帶上 self 參數(shù)變量。區(qū)別于在類中調(diào)用普通函數(shù)時并不需要帶上 self 參數(shù) ### 42.super 函數(shù)的作用 super() 函數(shù)是用于調(diào)用父類(超類)的一個方法 ```Python class A(): def funcA(self): print("this is func A") class B(A): def funcA_in_B(self): super(B, self).funcA() def funcC(self): print("this is func C") ins = B() ins.funcA_in_B() ins.funcC() ``` output ```Text this is func A this is func C ``` ### 43.類中的各種函數(shù) 主要分為實(shí)例方法、類方法和靜態(tài)方法 **實(shí)例方法** 定義:第一個參數(shù)必須是實(shí)例對象,該參數(shù)名一般約定為“self”,通過它來傳遞實(shí)例的屬性和方法(也可以傳類的屬性和方法) 調(diào)用:只能由實(shí)例對象調(diào)用 **類方法** 定義:使用裝飾器@classmethod。第一個參數(shù)必須是當(dāng)前類對象,該參數(shù)名一般約定為“cls”,通過它來傳遞類的屬性和方法(不能傳實(shí)例的屬性和方法) 調(diào)用:實(shí)例對象和類對象都可以調(diào)用 **靜態(tài)方法** 定義:使用裝飾器@staticmethod。參數(shù)隨意,沒有“self”和“cls”參數(shù),但是方法體中不能使用類或?qū)嵗娜魏螌傩院头椒? 調(diào)用:實(shí)例對象和類對象都可以調(diào)用 靜態(tài)方法是類中的函數(shù),不需要實(shí)例。靜態(tài)方法主要是用來存放邏輯性的代碼,主要是一些邏輯屬于類,但是和類本身沒有交互。即在靜態(tài)方法中,不會涉及到類中的方法和屬性的操作??梢岳斫鉃閷㈧o態(tài)方法存在此類的名稱空間中 類方法是將類本身作為對象進(jìn)行操作的方法。他和靜態(tài)方法的區(qū)別在于:不管這個方式是從實(shí)例調(diào)用還是從類調(diào)用,它都用第一個參數(shù)把類傳遞過來 ### 44.如何判斷是函數(shù)還是方法 與類和實(shí)例無綁定關(guān)系的 function 都屬于函數(shù)(function) 與類和實(shí)例有綁定關(guān)系的 function 都屬于方法(method) 普通函數(shù): ```Python def func1(): pass print(func1) output 類中的函數(shù): class People(object): def func2(self): pass @staticmethod def func3(): pass @classmethod def func4(cls): pass people = People() print(people.func2) print(people.func3) print(people.func4) ``` output ```Text > > ``` ### 45.isinstance 的作用以及與 type()的區(qū)別 isinstance() 函數(shù)來判斷一個對象是否是一個已知的類型,類似 type() 區(qū)別: type() 不會認(rèn)為子類是一種父類類型,不考慮繼承關(guān)系 isinstance() 會認(rèn)為子類是一種父類類型,考慮繼承關(guān)系 ```Python class A(object): pass class B(A): pass a = A() b = B() print(isinstance(a, A)) print(isinstance(b, A)) print(type(a) == A) print(type(b) == A) ``` output ```Text True True True False ``` ### 46.單例模式與工廠模式 單例模式:主要目的是確保某一個類只有一個實(shí)例存在 工廠模式:包涵一個超類,這個超類提供一個抽象化的接口來創(chuàng)建一個特定類型的對象,而不是決定哪個對象可以被創(chuàng)建 ### 47.查看目錄下的所有文件 ```Python import os print(os.listdir('.')) ``` ### 48.計(jì)算1到5組成的互不重復(fù)的三位數(shù) ```Python # 1到5組成的互不重復(fù)的三位數(shù) k = 0 for i in range(1, 6): for j in range(1, 6): for z in range(1, 6): if (i != j) and (i != z) and (j != z): k += 1 if k%6: print("%s%s%s" %(i, j, z), end="|") else: print("%s%s%s" %(i, j, z)) ``` output ```Text 123|124|125|132|134|135 142|143|145|152|153|154 213|214|215|231|234|235 241|243|245|251|253|254 312|314|315|321|324|325 341|342|345|351|352|354 412|413|415|421|423|425 431|432|435|451|452|453 512|513|514|521|523|524 531|532|534|541|542|543 ``` ### 49.去除字符串首尾空格 ```Python str1 = " hello nihao " str1.strip() ``` output ```Text 'hello nihao' ``` ### 50.去除字符串中間的空格 ```Python str2 = "hello you are good" print(str2.replace(" ", "")) "".join(str2.split(" ")) ``` output ```Text helloyouaregood 'helloyouaregood' ``` ### 51. 字符串格式化方式 1. 使用 % 操作符 ```Python print("This is for %s" % "Python") print("This is for %s, and %s" %("Python", "You")) ``` output ```Text This is for Python This is for Python, and You ``` 2. str.format 在 Python3 中,引入了這個新的字符串格式化方法 ```Python print("This is my {}".format("chat")) print("This is {name}, hope you can {do}".format(name="zhouluob", do="like")) ``` output ```Text This is my chat This is zhouluob, hope you can like ``` 3. f-strings 在 Python3-6 中,引入了這個新的字符串格式化方法 ```Python name = "luobodazahui" print(f"hello {name}") ``` output ```Text hello luobodazahui ``` 一個復(fù)雜些的例子: ```Python def mytest(name, age): return f"hello {name}, you are {age} years old!" people = mytest("luobo", 20) print(people) ``` output ```Text hello luobo, you are 20 years old! ``` ### 52. 將"hello world"轉(zhuǎn)換為首字母大寫"Hello World"(不使用 title 函數(shù)) ```Python str1 = "hello world" print(str1.title()) " ".join(list(map(lambda x: x.capitalize(), str1.split(" ")))) ``` output ```Text Hello World 'Hello World' ``` ### 53. 一行代碼轉(zhuǎn)換列表中的整數(shù)為字符串 如:[1, 2, 3] -> ["1", "2", "3"] ```Python list1 = [1, 2, 3] list(map(lambda x: str(x), list1)) ``` output ```Text ['1', '2', '3'] ``` ### 54. 合并兩個元組到字典 如:("zhangfei", "guanyu"),(66, 80) -> {'zhangfei': 66, 'guanyu': 80} ```Python a = ("zhangfei", "guanyu") b = (66, 80) dict(zip(a,b)) ``` output ```Text {'zhangfei': 66, 'guanyu': 80} ``` ### 55. 給出如下代碼的輸入,并簡單解釋 例子1: ```Python a = (1,2,3,[4,5,6,7],8) a[3] = 2 ``` output ```Text --------------------------------------------------------------------------- TypeError Traceback (most recent call last) in 1 a = (1,2,3,[4,5,6,7],8) ----> 2 a[3] = 2 3 #a TypeError: 'tuple' object does not support item assignment ``` 例子2: ```Python a = (1,2,3,[4,5,6,7],8) a[3][2] = 2 a ``` output ```Text (1, 2, 3, [4, 5, 2, 7], 8) ``` 從例子1的報(bào)錯中也可以看出,tuple 是不可變類型,不能改變 tuple 里的元素,例子2中,list 是可變類型,改變其元素是允許的 ### 56. Python 中的反射 反射就是通過字符串的形式,導(dǎo)入模塊;通過字符串的形式,去模塊尋找指定函數(shù),并執(zhí)行。利用字符串的形式去對象(模塊)中操作(查找/獲取/刪除/添加)成員,一種基于字符串的事件驅(qū)動! 簡單理解就是用來判斷某個字符串是什么,是變量還是方法 ```Python class NewClass(object): def __init__(self, name, male): self.name = name self.male = male def myname(self): print(f'My name is {self.name}') def mymale(self): print(f'I am a {self.male}') people = NewClass('luobo', 'boy') print(hasattr(people, 'name')) print(getattr(people, 'name')) setattr(people, 'male', 'girl') print(getattr(people, 'male')) ``` output ```Text True luobo girl ``` getattr,hasattr,setattr,delattr 對模塊的修改都在內(nèi)存中進(jìn)行,并不會影響文件中真實(shí)內(nèi)容 ### 57. 實(shí)現(xiàn)一個簡單的 API 使用 flask 構(gòu)造 web 服務(wù)器 ```Python from flask import Flask, request app = Flask(__name__) @app.route('/', methods=['POST']) def simple_api(): result = request.get_json() return result if __name__ == "__main__": app.run() ``` ### 58. metaclass 元類 類與實(shí)例: 首先定義類以后,就可以根據(jù)這個類創(chuàng)建出實(shí)例,所以:先定義類,然后創(chuàng)建實(shí)例 類與元類: 先定義元類, 根據(jù) metaclass 創(chuàng)建出類,所以:先定義 metaclass,然后創(chuàng)建類 ```Python class MyMetaclass(type): def __new__(cls, class_name, class_parents, class_attr): class_attr['print'] = "this is my metaclass's subclass %s" %class_name return type.__new__(cls, class_name, class_parents, class_attr) class MyNewclass(object, metaclass=MyMetaclass): pass myinstance = MyNewclass() myinstance.print ``` output ```Text "this is my metaclass's subclass MyNewclass" ``` ### 59. sort 和 sorted 的區(qū)別 sort() 是可變對象列表(list)的方法,無參數(shù),無返回值,sort() 會改變可變對象 ```Python dict1 = {'test1':1, 'test2':2} list1 = [2, 1, 3] print(list1.sort()) list1 ``` output ```Text None [1, 2, 3] ``` sorted() 是產(chǎn)生一個新的對象。sorted(L) 返回一個排序后的L,不改變原始的L,sorted() 適用于任何可迭代容器 ```Python dict1 = {'test1':1, 'test2':2} list1 = [2, 1, 3] print(sorted(dict1))print(sorted(list1)) ``` output ```Text ['test1', 'test2'] [1, 2, 3] ``` ### 60. Python 中的 GIL GIL 是 Python 的全局解釋器鎖,同一進(jìn)程中假如有多個線程運(yùn)行,一個線程在運(yùn)行 Python 程序的時候會占用 Python 解釋器(加了一把鎖即 GIL),使該進(jìn)程內(nèi)的其他線程無法運(yùn)行,等該線程運(yùn)行完后其他線程才能運(yùn)行。如果線程運(yùn)行過程中遇到耗時操作,則解釋器鎖解開,使其他線程運(yùn)行。所以在多線程中,線程的運(yùn)行仍是有先后順序的,并不是同時進(jìn)行 ### 61. 產(chǎn)生8位隨機(jī)密碼 ```Python import random "".join(random.choice(string.printable[:-7]) for i in range(8)) ``` output ```Text 'd5^NdNJp' ``` ### 62. 輸出原始字符 ```Python print('hello\nworld') print(b'hello\nworld') print(r'hello\nworld') ``` output ```Text hello world b'hello\nworld' hello\nworld ``` ### 63. 列表內(nèi),字典按照 value 大小排序 ```Python list1 = [{'name': 'guanyu', 'age':29}, {'name': 'zhangfei', 'age': 28}, {'name': 'liubei', 'age':31}] sorted(list1, key=lambda x:x['age']) ``` output ```Text [{'name': 'zhangfei', 'age': 28}, {'name': 'guanyu', 'age': 29}, {'name': 'liubei', 'age': 31}] ``` ### 64. 簡述 any() 和 all() 方法 all 如果存在 0 Null False 返回 False,否則返回 True;any 如果都是 0,None,F(xiàn)alse,Null 時,返回 True ```Python print(all([1, 2, 3, 0])) print(all([1, 2, 3])) print(any([1, 2, 3, 0])) print(any([0, None, False])) ``` output ```Text False True True False ``` ### 65. 反轉(zhuǎn)整數(shù) ```Python def reverse_int(x): if not isinstance(x, int): return False if -10 < x < 10: return x tmp = str(x) if tmp[0] != '-': tmp = tmp[::-1] return int(tmp) else: tmp = tmp[1:][::-1] x = int(tmp) return -x reverse_int(-23837) ``` output ```Text -73832 ``` 首先判斷是否是整數(shù),再判斷是否是一位數(shù)字,最后再判斷是不是負(fù)數(shù) ### 66. 函數(shù)式編程 函數(shù)式編程是一種抽象程度很高的編程范式,純粹的函數(shù)式編程語言編寫的函數(shù)沒有變量,因此,任意一個函數(shù),只要輸入是確定的,輸出就是確定的,這種純函數(shù)稱之為沒有副作用。而允許使用變量的程序設(shè)計(jì)語言,由于函數(shù)內(nèi)部的變量狀態(tài)不確定,同樣的輸入,可能得到不同的輸出,因此,這種函數(shù)是有副作用的。由于 Python 允許使用變量,因此,Python 不是純函數(shù)式編程語言 函數(shù)式編程的一個特點(diǎn)就是,允許把函數(shù)本身作為參數(shù)傳入另一個函數(shù),還允許返回一個函數(shù)! 函數(shù)作為返回值例子: ```Python def sum(*args): def inner_sum(): tmp = 0 for i in args: tmp += i return tmp return inner_sum mysum = sum(2, 4, 6) print(type(mysum)) mysum() ``` output ```Text 12 ``` ### 67. 簡述閉包 如果在一個內(nèi)部函數(shù)里,對在外部作用域(但不是在全局作用域)的變量進(jìn)行引用,那么內(nèi)部函數(shù)就被認(rèn)為是閉包(closure) 附上函數(shù)作用域圖片 ![](https://upload-images.jianshu.io/upload_images/5803165-110e6222c6c5fbb1.png) 閉包特點(diǎn) 1.必須有一個內(nèi)嵌函數(shù) 2.內(nèi)嵌函數(shù)必須引用外部函數(shù)中的變量 3.外部函數(shù)的返回值必須是內(nèi)嵌函數(shù) ### 68. 簡述裝飾器 裝飾器是一種特殊的閉包,就是在閉包的基礎(chǔ)上傳遞了一個函數(shù),然后覆蓋原來函數(shù)的執(zhí)行入口,以后調(diào)用這個函數(shù)的時候,就可以額外實(shí)現(xiàn)一些功能了 一個打印 log 的例子: ```Python import time def log(func): def inner_log(*args, **kw): print("Call: {}".format(func.__name__)) return func(*args, **kw) return inner_log @log def timer(): print(time.time()) timer() ``` output ```Text Call: timer 1560171403.5128365 ``` 本質(zhì)上,decorator就是一個返回函數(shù)的高階函數(shù) ### 69. 協(xié)程的優(yōu)點(diǎn) 子程序切換不是線程切換,而是由程序自身控制 沒有線程切換的開銷,和多線程比,線程數(shù)量越多,協(xié)程的性能優(yōu)勢就越明顯 不需要多線程的鎖機(jī)制,因?yàn)橹挥幸粋€線程,也不存在同時寫變量沖突,在協(xié)程中控制共享資源不加鎖 ### 70. 實(shí)現(xiàn)一個斐波那契數(shù)列 斐波那契數(shù)列: 又稱黃金分割數(shù)列,指的是這樣一個數(shù)列:1、1、2、3、5、8、13、21、34、……在數(shù)學(xué)上,斐波納契數(shù)列以如下被以遞歸的方法定義:F(1)=1,F(xiàn)(2)=1, F(n)=F(n-1)+F(n-2)(n>=2,n∈N*) 生成器法: ```Python def fib(n): if n == 0: return False if not isinstance(n, int) or (abs(n) != n): # 判斷是正整數(shù) return False a, b = 0, 1 while n: a, b = b, a+b n -= 1 yield a [i for i in fib(10)] ``` output ```Text [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] ``` 遞歸法: ```Python def fib(n): if n == 0: return False if not isinstance(n, int) or (abs(n) != n): return False if n <= 1: return n return fib(n-1)+ fib(n-2) [fib(i) for i in range(1, 11)] ``` output ```Text [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] ``` ### 71. 正則切分字符串 ```Python import re str1 = 'hello world:luobo dazahui' result = re.split(r":| ", str1) print(result) ``` output ```Text ['hello', 'world', 'luobo', 'dazahui'] ``` ### 72. yield 用法 yield 是用來生成迭代器的語法,在函數(shù)中,如果包含了 yield,那么這個函數(shù)就是一個迭代器。當(dāng)代碼執(zhí)行至 yield 時,就會中斷代碼執(zhí)行,直到程序調(diào)用 next() 函數(shù)時,才會在上次 yield 的地方繼續(xù)執(zhí)行 ```Python def foryield(): print("start test yield") while True: result = yield 5 print("result:", result) g = foryield() print(next(g)) print("*"*20) print(next(g)) ``` output ```Text start test yield 5 ******************** result: None 5 ``` 可以看到,第一個調(diào)用 next() 函數(shù),程序只執(zhí)行到了 "result = yield 5" 這里,同時由于 yield 中斷了程序,所以 result 也沒有被賦值,所以第二次執(zhí)行 next() 時,result 是 None ### 73. 冒泡排序 ```Python list1 = [2, 5, 8, 9, 3, 11] def paixu(data, reverse=False): if not reverse: for i in range(len(data) - 1): for j in range(len(data) - 1 - i): if data[j] > data[j+1]: data[j], data[j+1] = data[j+1], data[j] return data else: for i in range(len(data) - 1): for j in range(len(data) - 1 - i): if data[j] < data[j+1]: data[j], data[j+1] = data[j+1], data[j] return data print(paixu(list1, reverse=True)) ``` output ```Text [11, 9, 8, 5, 3, 2] ``` ### 74. 快速排序 快排的思想:首先任意選取一個數(shù)據(jù)(通常選用數(shù)組的第一個數(shù))作為關(guān)鍵數(shù)據(jù),然后將所有比它小的數(shù)都放到它前面,所有比它大的數(shù)都放到它后面,這個過程稱為一趟快速排序,之后再遞歸排序兩邊的數(shù)據(jù) 挑選基準(zhǔn)值:從數(shù)列中挑出一個元素,稱為"基準(zhǔn)"(pivot) 分割:重新排序數(shù)列,所有比基準(zhǔn)值小的元素?cái)[放在基準(zhǔn)前面,所有比基準(zhǔn)值大的元素?cái)[在基準(zhǔn)后面(與基準(zhǔn)值相等的數(shù)可以到任何一邊) 在這個分割結(jié)束之后,對基準(zhǔn)值的排序就已經(jīng)完成 遞歸排序子序列:遞歸地將小于基準(zhǔn)值元素的子序列和大于基準(zhǔn)值元素的子序列排序 ```Python list1 = [8, 5, 1, 3, 2, 10, 11, 4, 12, 20] def partition(arr,low,high): i = ( low-1 ) # 最小元素索引 pivot = arr[high] for j in range(low , high): # 當(dāng)前元素小于或等于 pivot if arr[j] <= pivot: i = i+1 arr[i],arr[j] = arr[j],arr[i] arr[i+1],arr[high] = arr[high],arr[i+1] return ( i+1 ) def quicksort(arr,low,high): if low < high: pi = partition(arr,low,high) quicksort(arr, low, pi-1) quicksort(arr, pi+1, high) quicksort(list1, 0, len(list1)-1) print(list1) ``` output ```Text [1, 2, 3, 4, 5, 8, 10, 11, 12, 20] ``` ### 75. requests 簡介 該庫是發(fā)起 HTTP 請求的強(qiáng)大類庫,調(diào)用簡單,功能強(qiáng)大 ```Python import requests url = "http://www.luobodazahui.top" response = requests.get(url) # 獲得請求 response.encoding = "utf-8" # 改變其編碼 html = response.text # 獲得網(wǎng)頁內(nèi)容 binary__content = response.content # 獲得二進(jìn)制數(shù)據(jù) raw = requests.get(url, stream=True) # 獲得原始響應(yīng)內(nèi)容 headers = {'user-agent': 'my-test/0.1.1'} # 定制請求頭 r = requests.get(url, headers=headers) cookies = {"cookie": "# your cookie"} # cookie的使用 r = requests.get(url, cookies=cookies) ``` ### 76. 比較兩個 json 數(shù)據(jù)是否相等 ```Python dict1 = {"zhangfei": 12, "guanyu": 13, "liubei": 18} dict2 = {"zhangfei": 12, "guanyu": 13, "liubei": 18} def compare_dict(dict1, dict2): issame = [] for k in dict1.keys(): if k in dict2: if dict1[k] == dict2[k]: issame.append(1) else: issame.append(2) else: issame.append(3) print(issame) sum_except = len(issame) sum_actually = sum(issame) if sum_except == sum_actually: print("this two dict are same!") return True else: print("this two dict are not same!") return False test = compare_dict(dict1, dict2) ``` output ```Text [1, 1, 1] this two dict are same! ``` ### 77. 讀取鍵盤輸入 ```Python input() 函數(shù) def forinput(): input_text = input() print("your input text is: ", input_text) forinput() ``` output ```Text hello your input text is: hello ``` ### 78. enumerate enumerate() 函數(shù)用于將一個可遍歷的數(shù)據(jù)對象(如列表、元組或字符串)組合為一個索引序列,同時列出數(shù)據(jù)和數(shù)據(jù)下標(biāo),一般用在 for 循環(huán)當(dāng)中 ```Python data1 = ['one', 'two', 'three', 'four'] for i, enu in enumerate(data1): print(i, enu) ``` output ```Text 0 one 1 two 2 three 3 four ``` ### 79. pass 語句 pass 是空語句,是為了保持程序結(jié)構(gòu)的完整性。pass 不做任何事情,一般用做占位語句 ```Python def forpass(n): if n == 1: pass else: print('not 1') forpass(1) ``` ### 80. 正則匹配郵箱 ```Python import re email_list= ["test01@163.com","test02@163.123", ".test03g@qq.com", "test04@gmail.com" ] for email in email_list: ret = re.match("[\w]{4,20}@(.*)\.com$",email) if ret: print("%s 是符合規(guī)定的郵件地址,匹配后結(jié)果是:%s" % (email,ret.group())) else: print("%s 不符合要求" % email) ``` output ```Text test01@163.com 是符合規(guī)定的郵件地址,匹配后結(jié)果是:test01@163.com test02@163.123 不符合要求 .test03g@qq.com 不符合要求 test04@gmail.com 是符合規(guī)定的郵件地址,匹配后結(jié)果是:test04@gmail.com ``` ### 81. 統(tǒng)計(jì)字符串中大寫字母的數(shù)量 ```Python str2 = 'werrQWSDdiWuW' counter = 0 for i in str2: if i.isupper(): counter += 1 print(counter) ``` output ```Text 6 ``` ### 82. json 序列化時保留中文 普通序列化: ```Python import json dict1 = {'name': '蘿卜', 'age': 18} dict1_new = json.dumps(dict1) print(dict1_new) ``` output ```Text {"name": "\u841d\u535c", "age": 18} ``` 保留中文 ```Python import json dict1 = {'name': '蘿卜', 'age': 18} dict1_new = json.dumps(dict1, ensure_ascii=False) print(dict1_new) ``` output ```Text {"name": "蘿卜", "age": 18} ``` ### 83. 簡述繼承 一個類繼承自另一個類,也可以說是一個孩子類/派生類/子類,繼承自父類/基類/超類,同時獲取所有的類成員(屬性和方法) 繼承使我們可以重用代碼,并且還可以更方便地創(chuàng)建和維護(hù)代碼 Python 支持以下類型的繼承: 單繼承- 一個子類類繼承自單個基類 多重繼承- 一個子類繼承自多個基類 多級繼承- 一個子類繼承自一個基類,而基類繼承自另一個基類 分層繼承- 多個子類繼承自同一個基類 混合繼承- 兩種或兩種以上繼承類型的組合 ### 84. 什么是猴子補(bǔ)丁 猴子補(bǔ)丁是指在運(yùn)行時動態(tài)修改類和模塊 猴子補(bǔ)丁主要有以下幾個用處: 在運(yùn)行時替換方法、屬性等 在不修改第三方代碼的情況下增加原來不支持的功能 在運(yùn)行時為內(nèi)存中的對象增加 patch 而不是在磁盤的源代碼中增加 ### 85. help() 函數(shù)和 dir() 函數(shù) help() 函數(shù)返回幫助文檔和參數(shù)說明: ```Python help(dict) ``` output ```Text Help on class dict in module builtins: class dict(object) | dict() -> new empty dictionary | dict(mapping) -> new dictionary initialized from a mapping object's | (key, value) pairs | dict(iterable) -> new dictionary initialized as if via: | d = {} | for k, v in iterable: | d[k] = v | dict(**kwargs) -> new dictionary initialized with the name=value pairs | in the keyword argument list. For example: dict(one=1, two=2) ...... ``` dir() 函數(shù)返回對象中的所有成員 (任何類型) ```Python dir(dict) ``` output ```Text ['__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', ...... ``` ### 86. 解釋 Python 中的`//`,`%`和`**`運(yùn)算符 `//` 運(yùn)算符執(zhí)行地板除法,返回結(jié)果的整數(shù)部分 (向下取整) `%` 是取模符號,返回除法后的余數(shù) `**` 符號表示取冪. a**b 返回 a 的 b 次方 ```Python print(5//3) print(5/3) print(5%3) print(5**3) ``` output ```Text 1 1.6666666666666667 2 125 ``` ### 87. 主動拋出異常 使用 raise ```Python def test_raise(n): if not isinstance(n, int): raise Exception('not a int type') else: print('good') test_raise(8.9) ``` output ```Text --------------------------------------------------------------------------- Exception Traceback (most recent call last) in 4 else: 5 print('good') ----> 6 test_raise(8.9) in test_raise(n) 1 def test_raise(n): 2 if not isinstance(n, int): ----> 3 raise Exception('not a int type') 4 else: 5 print('good') Exception: not a int type ``` ### 88. tuple 和 list 轉(zhuǎn)換 ```Python tuple1 = (1, 2, 3, 4) list1 = list(tuple1) print(list1) tuple2 = tuple(list1) print(tuple2) ``` output ```Text [1, 2, 3, 4](1, 2, 3, 4) ``` ### 89. 簡述斷言 Python 的斷言就是檢測一個條件,如果條件為真,它什么都不做;反之它觸發(fā)一個帶可選錯誤信息的 AssertionError ```Python def testassert(n): assert n == 2, "n is not 2" print('n is 2') testassert(1) ``` output ```Text --------------------------------------------------------------------------- AssertionError Traceback (most recent call last) in 2 assert n == 2, "n is not 2" 3 print('n is 2') ----> 4 testassert(1) in testassert(n) 1 def testassert(n): ----> 2 assert n == 2, "n is not 2" 3 print('n is 2') 4 testassert(1) AssertionError: n is not 2 ``` ### 90. 什么是異步非阻塞 同步異步指的是調(diào)用者與被調(diào)用者之間的關(guān)系 所謂同步,就是在發(fā)出一個功能調(diào)用時,在沒有得到結(jié)果之前,該調(diào)用就不會返回,一旦調(diào)用返回,就得到了返回值 異步的概念和同步相對,調(diào)用在發(fā)出之后,這個調(diào)用就直接返回了,所以沒有返回結(jié)果。當(dāng)該異步功能完成后,被調(diào)用者可以通過狀態(tài)、通知或回調(diào)來通知調(diào)用者 阻塞非阻塞是線程或進(jìn)程之間的關(guān)系 阻塞調(diào)用是指調(diào)用結(jié)果返回之前,當(dāng)前線程會被掛起(如遇到io操作)。調(diào)用線程只有在得到結(jié)果之后才會返回。函數(shù)只有在得到結(jié)果之后才會將阻塞的線程激活 非阻塞和阻塞的概念相對應(yīng),非阻塞調(diào)用指在不能立刻得到結(jié)果之前也會立刻返回,同時該函數(shù)不會阻塞當(dāng)前線程 ### 91. 什么是負(fù)索引 Python 中的序列是有索引的,它由正數(shù)和負(fù)數(shù)組成。正的數(shù)字使用'0'作為第一個索引,'1'作為第二個索引,以此類推 負(fù)數(shù)的索引從'-1'開始,表示序列中的最后一個索引,' - 2'作為倒數(shù)第二個索引,依次類推 ### 92. 退出 Python 后,內(nèi)存是否全部釋放 不是的,那些具有對象循環(huán)引用或者全局命名空間引用的變量,在 Python 退出時往往不會被釋放 另外不會釋放 C 庫保留的部分內(nèi)容 ### 93. Flask 和 Django 的異同 Flask 是 “microframework”,主要用來編寫小型應(yīng)用程序,不過隨著 Python 的普及,很多大型程序也在使用 Flask。同時,在 Flask 中,我們必須使用外部庫 Django 適用于大型應(yīng)用程序。它提供了靈活性,以及完整的程序框架和快速的項(xiàng)目生成方法??梢赃x擇不同的數(shù)據(jù)庫,URL結(jié)構(gòu),模板樣式等 ### 94. 創(chuàng)建刪除操作系統(tǒng)上的文件 ```Python import os f = open('test.txt', 'w') f.close() os.listdir() os.remove('test.txt') ``` ### 95. 簡述 logging 模塊 logging 模塊是 Python 內(nèi)置的標(biāo)準(zhǔn)模塊,主要用于輸出運(yùn)行日志,可以設(shè)置輸出日志的等級、日志保存路徑、日志文件回滾等;相比 print,具備如下優(yōu)點(diǎn): 可以通過設(shè)置不同的日志等級,在 release 版本中只輸出重要信息,而不必顯示大量的調(diào)試信息 print 將所有信息都輸出到標(biāo)準(zhǔn)輸出中,嚴(yán)重影響開發(fā)者從標(biāo)準(zhǔn)輸出中查看其它數(shù)據(jù);logging 則可以由開發(fā)者決定將信息輸出到什么地方,以及怎么輸出 簡單配置: ```Python import logging logging.debug("debug log") logging.info("info log") logging.warning("warning log") logging.error("error log") logging.critical("critica log") ``` output ```Text WARNING:root:warning log ERROR:root:error log CRITICAL:root:critica log ``` 默認(rèn)情況下,只顯示了大于等于WARNING級別的日志。logging.basicConfig()函數(shù)調(diào)整日志級別、輸出格式等 ### 96. 統(tǒng)計(jì)字符串中單詞出現(xiàn)次數(shù) ```Python from collections import Counter str1 = "nihsasehndciswemeotpxc" print(Counter(str1)) ``` output ```Text Counter({'s': 3, 'e': 3, 'n': 2, 'i': 2, 'h': 2, 'c': 2, 'a': 1, 'd': 1, 'w': 1, 'm': 1, 'o': 1, 't': 1, 'p': 1, 'x': 1}) ``` ### 97. 正則 re.complie 的作用 re.compile 是將正則表達(dá)式編譯成一個對象,加快速度,并重復(fù)使用 ### 98. try except else finally 的意義 try..except..else 沒有捕獲到異常,執(zhí)行 else 語句 try..except..finally 不管是否捕獲到異常,都執(zhí)行 finally 語句 ### 99.反轉(zhuǎn)列表 使用切片: ```Python $ python -m timeit -n 1000000 -s 'import numpy as np' 'mylist=list(np.arange(0, 200))' 'mylist[::-1]' 1000000 loops, best of 5: 15.6 usec per loop ``` 使用 reverse(): ```Python $ python -m timeit -n 1000000 -s 'import numpy as np' 'mylist=list(np.arange(0, 200))' 'mylist.reverse()' 1000000 loops, best of 5: 10.7 usec per loop ``` 這兩種方法都可以反轉(zhuǎn)列表,但需要注意的是內(nèi)置函數(shù) reverse() 會更改原始列表,而切片方法會創(chuàng)建一個新列表。 顯然,內(nèi)置函數(shù) reverse() 比列表切片方法更快! ### 100. 字符串中數(shù)字替換 使用 re 正則替換 ```Python import re str1 = '我是周蘿卜,今年18歲' result = re.sub(r"\d+","20",str1) print(result) ``` output ```Text 我是周蘿卜,今年20歲 ``` ## 綜合篇:網(wǎng)絡(luò)編程 ### 101. 簡述 OSI 七層協(xié)議 是網(wǎng)絡(luò)傳輸協(xié)議,人為的把網(wǎng)絡(luò)傳輸?shù)牟煌A段劃分成不同的層次 七層劃分為:應(yīng)用層、表示層、會話層、傳輸層、網(wǎng)絡(luò)層、數(shù)據(jù)鏈路層、物理層 五層劃分為:應(yīng)用層、傳輸層、網(wǎng)絡(luò)層、數(shù)據(jù)鏈路層、物理層 物理層:網(wǎng)線,電纜等物理設(shè)備 數(shù)據(jù)鏈路層:Mac 地址 網(wǎng)絡(luò)層:IP 地址 傳輸層:TCP,UDP 協(xié)議 應(yīng)用層:FTP 協(xié)議,Email,WWW 等 ### 102. 三次握手、四次揮手的流程 都發(fā)生在傳輸層 三次握手: TCP 協(xié)議是主機(jī)對主機(jī)層的傳輸控制協(xié)議,提供可靠的連接服務(wù),采用三次握手確認(rèn)建立一個連接。 TCP 標(biāo)志位(位碼),有6種標(biāo)示:SYN(synchronous建立聯(lián)機(jī)) ACK(acknowledgement 確認(rèn)) PSH(push傳送) FIN(finish結(jié)束) RST(reset重置) URG(urgent緊急) Sequence number(順序號碼) Acknowledge number(確認(rèn)號碼) 第一次握手:主機(jī) A 發(fā)送位碼為 syn=1,隨機(jī)產(chǎn)生 seq number=1234567 的數(shù)據(jù)包到服務(wù)器,并進(jìn)入 SYN_SEND 狀態(tài),主機(jī) B 由 SYN=1 知道,A 要求建立聯(lián)機(jī) 第二次握手:主機(jī) B 收到請求后要確認(rèn)聯(lián)機(jī)信息,向 A 發(fā)送 ack number=(主機(jī) A 的 seq+1),syn=1,ack=1,隨機(jī)產(chǎn)生 seq=7654321 的包,并進(jìn)入 SYN_RECV 狀態(tài) 第三次握手:主機(jī) A 收到后檢查 ack number 是否正確,即第一次發(fā)送的 seq number+1,以及位碼 ack 是否為 1,若正確,主機(jī) A 會再發(fā)送 ack number=(主機(jī) B 的 seq+1),ack=1,主機(jī) B 收到后確認(rèn) seq 值與 ack=1 則連接建立成功,兩個主機(jī)均進(jìn)入 ESTABLISHED 狀態(tài) 以上完成三次握手,主機(jī) A 與主機(jī) B 開始傳送數(shù)據(jù) 四次揮手: 因?yàn)?TCP 連接是全雙工的,因此每個方向都必須單獨(dú)進(jìn)行關(guān)閉。這個原則是當(dāng)一方完成它的數(shù)據(jù)發(fā)送任務(wù)后就能發(fā)送一個 FIN 來終止這個方向的連接。收到一個 FIN 只意味著這一方向上沒有數(shù)據(jù)流動,一個 TCP 連接在收到一個 FIN 后仍能發(fā)送數(shù)據(jù)。首先進(jìn)行關(guān)閉的一方將執(zhí)行主動關(guān)閉,而另一方執(zhí)行被動關(guān)閉 服務(wù)器 A 發(fā)送一個 FIN,用來關(guān)閉 A 到服務(wù)器 B 的數(shù)據(jù)傳送。 服務(wù)器 B 收到這個 FIN,它發(fā)回一個 ACK,確認(rèn)序號為收到的序號加1。和 SYN 一樣,一個 FIN 將占用一個序號 服務(wù)器 B 關(guān)閉與服務(wù)器 A 的連接,發(fā)送一個 FIN 給服務(wù)器 A 服務(wù)器 A 發(fā)回 ACK 報(bào)文確認(rèn),并將確認(rèn)序號設(shè)置為收到序號加1 ### 103. 什么是 C/S 和 B/S 架構(gòu) B/S 又稱為瀏覽器/服務(wù)器模式。比如各種網(wǎng)站,jupyter notebook 等。 優(yōu)點(diǎn):零安裝,維護(hù)簡單,共享性好。 缺點(diǎn):安全性較差,個性化不足 C/S 又稱為客戶端/服務(wù)器模式。比如微信客戶端,Oracle 客戶端等。 優(yōu)點(diǎn):安全性好,數(shù)據(jù)傳輸較快,穩(wěn)定。 缺點(diǎn):對 PC 機(jī)操作系統(tǒng)等有要求,當(dāng)客戶端較多時,服務(wù)器端負(fù)載較大 ### 104. TCP 和 UDP 的區(qū)別 TCP 和 UDP 都是 OSI 模型中運(yùn)輸層的協(xié)議。TCP 提供可靠的通信傳輸,而 UDP 則常被用于廣播和細(xì)節(jié)控制交給應(yīng)用的通信傳輸。 UDP 不提供復(fù)雜的控制機(jī)制,利用 IP 提供面向無連接的通信服務(wù)。 TCP 充分實(shí)現(xiàn)了數(shù)據(jù)傳輸時各種控制功能,可以進(jìn)行丟包的重發(fā)控制,還可以對次序亂掉的分包進(jìn)行順序控制 TCP 應(yīng)用:FTP 傳輸,點(diǎn)對點(diǎn)短信等 UDP 應(yīng)用:媒體流等 ### 105. 局域網(wǎng)和廣域網(wǎng) 廣域網(wǎng)(WAN,Wide Area Network)也稱遠(yuǎn)程網(wǎng)(long haul network )。通常跨接很大的物理范圍,所覆蓋的范圍從幾十公里到幾千公里,它能連接多個城市或國家,或橫跨幾個洲并能提供遠(yuǎn)距離通信,形成國際性的遠(yuǎn)程網(wǎng)絡(luò) 域網(wǎng)(Local Area Network,LAN)是指在某一區(qū)域內(nèi)由多臺計(jì)算機(jī)互聯(lián)成的計(jì)算機(jī)組。一般是方圓幾千米以內(nèi)。局域網(wǎng)可以實(shí)現(xiàn)文件管理、應(yīng)用軟件共享、打印機(jī)共享、工作組內(nèi)的日程安排、電子郵件和傳真通信服務(wù)等功能。局域網(wǎng)是封閉型的,可以由辦公室內(nèi)的兩臺計(jì)算機(jī)組成,也可以由一個公司內(nèi)的上千臺計(jì)算機(jī)組成 ### 106. arp 協(xié)議 ARP(Address Resolution Protocol)即地址解析協(xié)議, 用于實(shí)現(xiàn)從 IP 地址到 MAC 地址的映射,即詢問目標(biāo) IP 對應(yīng)的 MAC 地址 ### 107. 什么是 socket?簡述基于 TCP 協(xié)議的套接字通信流程 socket 是對 TCP/IP 協(xié)議的封裝,它的出現(xiàn)只是使得程序員更方便地使用 TCP/IP 協(xié)議棧而已。socket 本身并不是協(xié)議,它是應(yīng)用層與 TCP/IP 協(xié)議族通信的中間軟件抽象層,是一組調(diào)用接口(TCP/IP網(wǎng)絡(luò)的API函數(shù)) “TCP/IP 只是一個協(xié)議棧,就像操作系統(tǒng)的運(yùn)行機(jī)制一樣,必須要具體實(shí)現(xiàn),同時還要提供對外的操作接口。 這個就像操作系統(tǒng)會提供標(biāo)準(zhǔn)的編程接口,比如win32編程接口一樣。TCP/IP 也要提供可供程序員做網(wǎng)絡(luò)開發(fā)所用的接口,這就是 Socket 編程接口?!? Server: ```Python import socket import threading def tcplink(sock, addr): print('Accept new connection from %s:%s...' % addr) sock.send(b'Welcome!') while True: data = sock.recv(1024) time.sleep(1) if not data or data.decode('utf-8') == 'exit': break sock.send(('Hello, %s!' % data.decode('utf-8')).encode('utf-8')) sock.close() print('Connection from %s:%s closed.' % addr) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 監(jiān)聽端口: s.bind(('127.0.0.1', 9999)) s.listen(5) print('Waiting for connection...') while True: # 接受一個新連接: sock, addr = s.accept() # 創(chuàng)建新線程來處理TCP連接: t = threading.Thread(target=tcplink, args=(sock, addr)) t.start() ``` Client: ```Python import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 建立連接: s.connect(('127.0.0.1', 9999)) # 接收歡迎消息: print(s.recv(1024).decode('utf-8')) for data in [b'Michael', b'Tracy', b'Sarah']: # 發(fā)送數(shù)據(jù): s.send(data) print(s.recv(1024).decode('utf-8')) s.send(b'exit') s.close() ``` 例子來源于廖雪峰的官網(wǎng) ### 108. 簡述 進(jìn)程、線程、協(xié)程的區(qū)別以及應(yīng)用場景 進(jìn)程是具有一定獨(dú)立功能的程序關(guān)于某個數(shù)據(jù)集合上的一次運(yùn)行活動,進(jìn)程是系統(tǒng)進(jìn)行資源分配和調(diào)度的一個獨(dú)立單位。每個進(jìn)程都有自己的獨(dú)立內(nèi)存空間,不同進(jìn)程通過進(jìn)程間通信來通信 線程是進(jìn)程的一個實(shí)體,是CPU調(diào)度和分派的基本單位,它是比進(jìn)程更小的能獨(dú)立運(yùn)行的基本單位。線程自己基本上不擁有系統(tǒng)資源,只擁有一點(diǎn)在運(yùn)行中必不可少的資源(如程序計(jì)數(shù)器,一組寄存器和棧),但是它可與同屬一個進(jìn)程的其他的線程共享進(jìn)程所擁有的全部資源 協(xié)程是一種用戶態(tài)的輕量級線程,協(xié)程的調(diào)度完全由用戶控制。協(xié)程擁有自己的寄存器上下文和棧 多進(jìn)程:密集 CPU 任務(wù),需要充分使用多核 CPU 資源(服務(wù)器,大量的并行計(jì)算)的時候,用多進(jìn)程。 缺陷:多個進(jìn)程之間通信成本高,切換開銷大 多線程:密集 I/O 任務(wù)(網(wǎng)絡(luò) I/O,磁盤 I/O,數(shù)據(jù)庫 I/O)使用多線程合適。 缺陷:同一個時間切片只能運(yùn)行一個線程,不能做到高并行,但是可以做到高并發(fā) 協(xié)程:又稱微線程,在單線程上執(zhí)行多個任務(wù),用函數(shù)切換,開銷極小。不通過操作系統(tǒng)調(diào)度,沒有進(jìn)程、線程的切換開銷。缺陷:單線程執(zhí)行,處理密集 CPU 和本地磁盤 IO 的時候,性能較低。處理網(wǎng)絡(luò) I/O 性能還是比較高 多線程請求返回是無序的,哪個線程有數(shù)據(jù)返回就處理哪個線程,而協(xié)程返回的數(shù)據(jù)是有序的 ### 109. 如何使用線程池和進(jìn)程池 池的功能是限制啟動的進(jìn)程數(shù)或線程數(shù)。當(dāng)并發(fā)的任務(wù)數(shù)遠(yuǎn)遠(yuǎn)超過了計(jì)算機(jī)的承受能力時,即無法一次性開啟過多的進(jìn)程數(shù)或線程數(shù)時,就應(yīng)該用池的概念將開啟的進(jìn)程數(shù)或線程數(shù)限制在計(jì)算機(jī)可承受的范圍內(nèi) 多進(jìn)程 ```Python from multiprocessing import Pool import os import time import random def long_time_task(name): print('Run task %s (%s)...' % (name, os.getpid())) start = time.time() time.sleep(random.random() * 3) end = time.time() print('Task %s runs %0.2f seconds.' % (name, (end - start))) def test_pool(): print('Parent process %s.' % os.getpid()) p = Pool(4) for i in range(5): p.apply_async(long_time_task, args=(i,)) print('Waiting for all subprocesses done...') p.close() p.join() print('All subprocesses done.') if __name__ == '__main__': test_pool() ``` output ```Text Parent process 32432. Waiting for all subprocesses done... Run task 0 (15588)... Run task 1 (32372)... Run task 2 (12440)... Run task 3 (18956)... Task 2 runs 0.72 seconds. Run task 4 (12440)... Task 3 runs 0.82 seconds. Task 1 runs 1.21 seconds. Task 0 runs 3.00 seconds. Task 4 runs 2.95 seconds. All subprocesses done. ``` apply_async(func[, args[, kwds]]) :使用非阻塞方式調(diào)用 func(并行執(zhí)行,堵塞方式必須等待上一個進(jìn)程退出才能執(zhí)行下一個進(jìn)程),args 為傳遞給 func 的參數(shù)列表,kwds 為傳遞給 func 的關(guān)鍵字參數(shù)列表; close():關(guān)閉 Pool,使其不再接受新的任務(wù); terminate():不管任務(wù)是否完成,立即終止; join():主進(jìn)程阻塞,等待子進(jìn)程的退出, 必須在 close 或 terminate 之后使用 也可以使用 concurrent.futures 模塊提供的功能來實(shí)現(xiàn) ```Python def test_future_process(): print('Parent process %s.' % os.getpid()) p = ProcessPoolExecutor(4) for i in range(5): p.submit(long_time_task, i) p.shutdown(wait=True) print('Finish') if __name__ == '__main__': # test_pool() test_future_process() ``` output ```Text Parent process 29368. Run task 0 (32148)... Run task 1 (31552)... Run task 2 (24012)... Run task 3 (29408)... Task 2 runs 0.52 seconds. Run task 4 (24012)... Task 3 runs 0.86 seconds. Task 1 runs 1.81 seconds. Task 0 runs 1.83 seconds. Task 4 runs 1.69 seconds. Finish ``` 多線程 ```Python def sayhello(a): print("hello: " + a) start = time.time() time.sleep(random.random() * 3) end = time.time() print('Task %s runs %0.2f seconds.' % (a, (end - start))) def test_future_thread(): seed = ["a", "b", "c", "d"] start = time.time() with ThreadPoolExecutor(3) as executor: for i in seed: executor.submit(sayhello, i) end = time.time() print("Thread Run Time: " + str(end - start)) ``` output ```Text hello: a hello: b hello: c Task a runs 0.40 seconds. hello: d Task b runs 0.56 seconds. Task d runs 1.70 seconds. Task c runs 2.92 seconds. Thread Run Time: 2.9195945262908936 ``` 可以看出,由于是創(chuàng)建了限制為3的線程池,所以只有三個任務(wù)在同時執(zhí)行 ### 110. 進(jìn)程之間如何進(jìn)行通信 ```Python def write(q): print("write(%s), 父進(jìn)程為(%s)" % (os.getpid(), os.getppid())) for i in "Python": print("Put %s to Queue" % i) q.put(i) def read(q): print("read(%s), 父進(jìn)程為(%s)" % (os.getpid(), os.getppid())) for i in range(q.qsize()): print("read 從 Queue 獲取到消息: %s" % q.get(True)) def test_commun(): print("(%s) start" % os.getpid()) q = Manager().Queue() pw = Process(target=write, args=(q, )) pr = Process(target=read, args=(q, )) pw.start() pr.start() pw.join() pr.terminate() ``` output ```Text (23544) start write(29856), 父進(jìn)程為(23544) Put P to Queue Put y to Queue Put t to Queue Put h to Queue Put o to Queue Put n to Queue read(25016), 父進(jìn)程為(23544) read 從 Queue 獲取到消息: P read 從 Queue 獲取到消息: y read 從 Queue 獲取到消息: t read 從 Queue 獲取到消息: h read 從 Queue 獲取到消息: o read 從 Queue 獲取到消息: n ``` Python 的 multiprocessing 模塊包裝了底層的機(jī)制,提供了 Queue、Pipes 等多種方式來交換數(shù)據(jù) ### 111. 進(jìn)程鎖和線程鎖 進(jìn)程鎖:是為了控制同一操作系統(tǒng)中多個進(jìn)程訪問一個共享資源,只是因?yàn)槌绦虻莫?dú)立性,各個進(jìn)程是無法控制其他進(jìn)程對資源的訪問的,但是可以使用本地系統(tǒng)的信號量控制。 信號量(Semaphore),有時被稱為信號燈,是在多線程環(huán)境下使用的一種設(shè)施,是可以用來保證兩個或多個關(guān)鍵代碼段不被并發(fā)調(diào)用 線程鎖:當(dāng)多個線程幾乎同時修改一個共享數(shù)據(jù)的時候,需要進(jìn)行同步控制,線程同步能夠保證多個線程安全的訪問競爭資源(全局內(nèi)容),最簡單的同步機(jī)制就是使用互斥鎖。 某個線程要更改共享數(shù)據(jù)時,先將其鎖定,此時資源的狀態(tài)為鎖定狀態(tài),其他線程就能更改,直到該線程將資源狀態(tài)改為非鎖定狀態(tài),也就是釋放資源,其他的線程才能再次鎖定資源?;コ怄i保證了每一次只有一個線程進(jìn)入寫入操作。從而保證了多線程下數(shù)據(jù)的安全性 ### 112. 什么是并發(fā)和并行 并行:多個 CPU 核心,不同的程序就分配給不同的 CPU 來運(yùn)行。可以讓多個程序同時執(zhí)行 并發(fā):單個 CPU 核心,在一個時間切片里一次只能運(yùn)行一個程序,如果需要運(yùn)行多個程序,則串行執(zhí)行 ### 113. threading.local 的作用 ThreadLocal 叫做線程本地變量,ThreadLocal 在每一個變量中都會創(chuàng)建一個副本,每個線程都可以訪問自己內(nèi)部的副本變量,對其他線程時不可見的,修改之后也不會影響到其他線程 ### 114. 什么是域名解析 域名解析是指將域名解析為 IP 地址。也有反向的“逆解析”,將 IP 通過 DNS 服務(wù)器查找到對應(yīng)的域名地址 DNS 是域名系統(tǒng) (Domain Name System),域名系統(tǒng)為因特網(wǎng)上的主機(jī)分配域名地址和 IP 地址。用戶使用域名地址,該系統(tǒng)就會自動把域名地址轉(zhuǎn)為 IP 地址 ### 115. LVS 是什么及作用 LVS 是 Linux Virtual Server 的簡寫,意即 Linux 虛擬服務(wù)器,是一個虛擬的服務(wù)器集群系統(tǒng),即負(fù)載均衡服務(wù)器 LVS 工作模式分為 NAT 模式、TUN 模式、以及 DR 模式 ### 116. Nginx 的作用 Nginx 主要功能:1、反向代理 2、負(fù)載均衡 3、HTTP 服務(wù)器(包含動靜分離) 4、正向代理 正向代理:某些情況下,代理用戶去訪問服務(wù)器,需要手動設(shè)置代理服務(wù)器的 IP 和端口號 反向代理:是用來代理服務(wù)器的,代理要訪問的目標(biāo)服務(wù)器。代理服務(wù)器接受請求,然后將請求轉(zhuǎn)發(fā)給內(nèi)部網(wǎng)絡(luò)的服務(wù)器(集群化),并將從服務(wù)器上得到的結(jié)果返回給客戶端,此時代理服務(wù)器對外就表現(xiàn)為一個服務(wù)器 負(fù)載均衡服務(wù)器類似于 LVS HTTP 服務(wù)器類似于 Tomcat 等 ### 117. keepalived 及 HAProxy HAProxy 提供高可用性、負(fù)載均衡,以及基于 TCP 和 HTTP 的應(yīng)用程序代理。 keepalived 是集群管理中保證集群高可用的一個服務(wù)軟件,其功能類似于 heartbeat,用來防止單點(diǎn)故障 ### 118. 什么是 rpc RPC 是指遠(yuǎn)程過程調(diào)用,也就是說兩臺服務(wù)器 A,B,一個應(yīng)用部署在 A 服務(wù)器上,想要調(diào)用 B 服務(wù)器上應(yīng)用提供的函數(shù)/方法,由于不在一個內(nèi)存空間,不能直接調(diào)用,需要通過網(wǎng)絡(luò)來表達(dá)調(diào)用的語義和傳達(dá)調(diào)用的數(shù)據(jù) ### 119. 從瀏覽器輸入一個網(wǎng)址到展示網(wǎng)址頁面的過程 瀏覽器通過 DNS 服務(wù)器查找到域名對應(yīng)的 IP 地址 瀏覽器給 IP 對應(yīng)的 web 服務(wù)器發(fā)送 HTTP 請求 web 服務(wù)器接收到 HTTP 請求后,返回響應(yīng)給瀏覽器 瀏覽器接收到響應(yīng)后渲染頁面 ### 120. 什么是cdn CDN 的全稱是 Content Delivery Network,即內(nèi)容分發(fā)網(wǎng)絡(luò)。CDN 是構(gòu)建在網(wǎng)絡(luò)之上的內(nèi)容分發(fā)網(wǎng)絡(luò),依靠部署在各地的邊緣服務(wù)器,通過中心平臺的負(fù)載均衡、內(nèi)容分發(fā)、調(diào)度等功能模塊,使用戶就近獲取所需內(nèi)容,降低網(wǎng)絡(luò)擁塞,提高用戶訪問響應(yīng)速度和命中率。CDN 的關(guān)鍵技術(shù)主要有內(nèi)容存儲和分發(fā)技術(shù) ## 綜合篇:數(shù)據(jù)庫和框架 ### 121. 列舉常見的數(shù)據(jù)庫 關(guān)系型數(shù)據(jù)庫:MySQL,Oracle,SQLServer,SQLite,DB2 非關(guān)系型數(shù)據(jù)庫:MongoDB,Redis,HBase,Neo4j ### 122. 數(shù)據(jù)庫設(shè)計(jì)三大范式 建立科學(xué)的,規(guī)范的的數(shù)據(jù)庫是需要滿足一些規(guī)范的,以此來優(yōu)化數(shù)據(jù)數(shù)據(jù)存儲方式,在關(guān)系型數(shù)據(jù)庫中這些規(guī)范就可以稱為范式 第一范式:當(dāng)關(guān)系模式 R 的所有屬性都不能在分解為更基本的數(shù)據(jù)單位時,稱 R 是滿足第一范式的,簡記為 1NF 關(guān)系模式R的所有屬性不能再分解 第二范式:如果關(guān)系模式 R 滿足第一范式,并且 R 的所有非主屬性都完全依賴于 R 的每一個候選關(guān)鍵屬性,稱 R 滿足第二范式,簡記為 2NF 非主屬性都要依賴于每一個關(guān)鍵屬性 三范式:設(shè) R 是一個滿足第一范式條件的關(guān)系模式,X 是 R 的任意屬性集,如果 X 非傳遞依賴于 R 的任意一個候選關(guān)鍵字,稱 R 滿足第三范式,簡記為 3NF 數(shù)據(jù)不能存在傳遞關(guān)系,即每個屬性都跟主鍵有直接關(guān)系而不是間接關(guān)系 ### 123. 什么是數(shù)據(jù)庫事務(wù) 事務(wù)(Transaction)是并發(fā)控制的基本單位。所謂的事務(wù),它是一個操作序列,這些操作要么都執(zhí)行,要么都不執(zhí)行,它是一個不可分割的工作單位 在關(guān)系數(shù)據(jù)庫中,一個事務(wù)可以是一條 SQL 語句、一組 SQL 語句或整個程序。 四個屬性:原子性,一致性,隔離性和持久性 ### 124. MySQL 索引種類 MySQL 目前主要有以下幾種索引類型: - 普通索引 - 唯一索引 - 主鍵索引 - 組合索引 - 全文索引 ### 125. 數(shù)據(jù)庫設(shè)計(jì)中一對多和多對多的應(yīng)用場景 一對一關(guān)系示例: 一個學(xué)生對應(yīng)一個學(xué)生檔案材料,或者每個人都有唯一的身份證編號 一對多關(guān)系示例: 一個學(xué)生只屬于一個班,但是一個班級有多名學(xué)生 多對多關(guān)系示例: 一個學(xué)生可以選擇多門課,一門課也有多名學(xué)生 ### 126. 簡述觸發(fā)器、函數(shù)、視圖、存儲過程 觸發(fā)器:觸發(fā)器是一個特殊的存儲過程,它是數(shù)據(jù)庫在 insert、update、delete 的時候自動執(zhí)行的代碼塊 函數(shù):數(shù)據(jù)庫中提供了許多內(nèi)置函數(shù),還可以自定義函數(shù),實(shí)現(xiàn) sql 邏輯 視圖:視圖是由查詢結(jié)果形成的一張?zhí)摂M表,是表通過某種運(yùn)算得到的一個投影 存儲過程:把一段代碼封裝起來,當(dāng)要執(zhí)行這一段代碼的時候,可以通過調(diào)用該存儲過程來實(shí)現(xiàn)(經(jīng)過第一次編譯后再次調(diào)用不需要再次編譯,比一個個執(zhí)行 sql 語句效率高) ### 127. 常用 SQL 語句 DML(數(shù)據(jù)操作語言) - SELECT - 從數(shù)據(jù)庫表中獲取數(shù)據(jù) - UPDATE - 更新數(shù)據(jù)庫表中的數(shù)據(jù) - DELETE - 從數(shù)據(jù)庫表中刪除數(shù)據(jù) - INSERT INTO - 向數(shù)據(jù)庫表中插入數(shù)據(jù) DDL(數(shù)據(jù)定義語言) - CREATE DATABASE - 創(chuàng)建新數(shù)據(jù)庫 - ALTER DATABASE - 修改數(shù)據(jù)庫 - CREATE TABLE - 創(chuàng)建新表 - ALTER TABLE - 變更(改變)數(shù)據(jù)庫表 - DROP TABLE - 刪除表 - CREATE INDEX - 創(chuàng)建索引(搜索鍵) - DROP INDEX - 刪除索引 ### 128. 主鍵和外鍵的區(qū)別 定義主鍵和外鍵主要是為了維護(hù)關(guān)系數(shù)據(jù)庫的完整性 主鍵是能確定一條記錄的唯一標(biāo)識。不能重復(fù),不允許為空 外鍵用于與另一張表關(guān)聯(lián)。是能確定另一張表記錄的字段,用于保持?jǐn)?shù)據(jù)的一致性 主鍵外鍵索引定義唯一標(biāo)識一條記錄,不能重復(fù),不允許為空表的外鍵是另一表的主鍵,外鍵可以重復(fù),可以是空值該字段沒有重復(fù)值,但可以有空值作用用來保證數(shù)據(jù)完整性用來和其他表建立聯(lián)系提高查詢排序的速度個數(shù)只能有一個可有多個可有多個 ### 129. 如何開啟 MySQL 慢日志查詢 修改配置文件,然后重啟服務(wù)生效 在linux下,vim /etc/my.cnf,在[mysqld]內(nèi)容項(xiàng)下增加: slow_query_log = ON long_query_time = 2 # 查詢超過2秒的就會記錄 命令行,但是重啟服務(wù)后會失效 SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 2; ### 130. MySQL 數(shù)據(jù)庫備份命令 mysqldump -u 用戶名 -p 數(shù)據(jù)庫名 > 導(dǎo)出的文件名 ### 131. char 和 varchar 的區(qū)別 char:存儲定長數(shù)據(jù)很方便,CHAR 字段上的索引效率級高,必須在括號里定義長度,可以有默認(rèn)值,比如定義 char(10) varchar:存儲變長數(shù)據(jù),但存儲效率沒有 CHAR 高,必須在括號里定義長度,可以有默認(rèn)值 ### 132. 最左前綴原則 mysql 建立多列索引(聯(lián)合索引)有最左前綴的原則,即最左優(yōu)先,如: 如果有一個2列的索引(col1,col2),則已經(jīng)對(col1)、(col1,col2)上建立了索引 如果有一個3列索引(col1,col2,col3),則已經(jīng)對(col1)、(col1,col2)、(col1,col2,col3)上建立了索引 ### 133. 無法命中索引的情況 使用or關(guān)鍵字會導(dǎo)致無法命中索引 左前導(dǎo)查詢會導(dǎo)致無法命中索引,如 like '%a' 或者 like '%a%' 單列索引的索引列為 null 時全值匹配會使索引失效,組合索引全為 null 時索引失效 組合索引不符合左前綴原則的列無法命中索引,如我們有4個列 a、b、c、d,我們創(chuàng)建一個組合索引 INDEX(a,b,c,d),那么能命中索引的查詢?yōu)?a,ab,abc,abcd,除此之外都無法命中索引 強(qiáng)制類型轉(zhuǎn)換會導(dǎo)致索引失效 負(fù)向查詢條件會導(dǎo)致無法使用索引,比如 NOT IN,NOT LIKE,!= 等 如果 mysql 估計(jì)使用全表掃描要比使用索引快,則不使用索引 ### 134. 數(shù)據(jù)庫讀寫分離 讀寫分離,就是將數(shù)據(jù)庫分為了主從庫,一個主庫用于寫數(shù)據(jù),多個從庫完成讀數(shù)據(jù)的操作,主從庫之間通過某種機(jī)制進(jìn)行數(shù)據(jù)的同步,是一種常見的數(shù)據(jù)庫架構(gòu) ### 135. 數(shù)據(jù)庫分庫分表 數(shù)據(jù)庫水平切分,是一種常見的數(shù)據(jù)庫架構(gòu),是一種通過算法,將數(shù)據(jù)庫進(jìn)行分割的架構(gòu)。一個水平切分集群中的每個數(shù)據(jù)庫,通常稱為一個“分片”。每一個分片中的數(shù)據(jù)沒有重合,所有分片中的數(shù)據(jù)并集組成全部數(shù)據(jù)。 水平切分分為庫內(nèi)分表和分庫分表,是根據(jù)表內(nèi)數(shù)據(jù)內(nèi)在的邏輯關(guān)系,將同一個表按不同的條件分散到多個數(shù)據(jù)庫或多個表中,每個表中只包含一部分?jǐn)?shù)據(jù),從而使得單個表的數(shù)據(jù)量變小,達(dá)到分布式的效果 ### 136. redis 和 memcached 比較 redis 和 memcached 都是將數(shù)據(jù)存放在內(nèi)存中,都是內(nèi)存數(shù)據(jù)庫。不過 memcached 還可用于緩存其他東西,例如圖片、視頻等等 redis 不僅僅支持簡單的 k/v 類型的數(shù)據(jù),同時還提供 list,set,hash 等數(shù)據(jù)結(jié)構(gòu)的存儲 分布式設(shè)定, 都可以做一主多從或一主一從 存儲數(shù)據(jù)安全,memcached 掛掉后,數(shù)據(jù)完全丟失;redis 可以定期保存到磁盤(持久化) 災(zāi)難恢復(fù),memcached 掛掉后,數(shù)據(jù)不可恢復(fù); redis 數(shù)據(jù)丟失后可以通過 aof 恢復(fù) ### 137. redis中數(shù)據(jù)庫默認(rèn)是多少個 db 及作用 redis 默認(rèn)有16個數(shù)據(jù)庫,每個數(shù)據(jù)庫中的數(shù)據(jù)都是隔離的,這樣,在存儲數(shù)據(jù)的時候,就可以指定把不同的數(shù)據(jù)存儲到不同的數(shù)據(jù)庫中。 且只有單機(jī)才有,如果是集群就沒有數(shù)據(jù)庫的概念 ### 138. redis 有哪幾種持久化策略 RDB 持久化:是將 Reids 在內(nèi)存中的數(shù)據(jù)庫記錄定時 dump 到磁盤上的持久化 AOF(append only file)持久化:將 Reids 的操作日志以追加的方式寫入文件 ### 139. redis 支持的過期策略 通用的三種過期策略 定時刪除 在設(shè)置 key 的過期時間的同時,為該 key 創(chuàng)建一個定時器,讓定時器在 key 的過期時間來臨時,對 key 進(jìn)行刪除 惰性刪除 key 過期的時候不刪除,每次從數(shù)據(jù)庫獲取 key 的時候去檢查是否過期,若過期,則刪除,返回 null 定期刪除 每隔一段時間執(zhí)行一次刪除過期 key 操作 redis 采用惰性刪除+定期刪除策略 ### 140. 如何保證 redis 中的數(shù)據(jù)都是熱點(diǎn)數(shù)據(jù) 限定 Redis 占用的內(nèi)存,Redis 會根據(jù)自身數(shù)據(jù)淘汰策略,加載熱數(shù)據(jù)到內(nèi)存。 所以,計(jì)算一下所有熱點(diǎn)數(shù)據(jù)大約占用的內(nèi)存,然后設(shè)置一下 Redis 內(nèi)存限制即可 ### 141. Python 操作 redis 使用 redis 第三方庫來操作 ```Python import redis # 創(chuàng)建一個 redis 連接池 def redis_conn_pool(): pool = redis.ConnectionPool(host='redis-host', port=redis-port, decode_responses=True, password='redis-pwd') r = redis.Redis(connection_pool=pool) return r ``` ### 142. 基于 redis 實(shí)現(xiàn)發(fā)布和訂閱 訂閱者 ```Python if __name__ == "__main__": conn = redis.Redis(host='', port=12143, password='') ps = conn.pubsub() ps.subscribe('chat') # 從 chat 訂閱消息 for item in ps.listen(): # 監(jiān)聽狀態(tài):有消息發(fā)布了就拿過來 if item['type'] == 'message': print(item) print(item['channel']) print(item['data']) ``` 發(fā)布者 ```Python if __name__ == "__main__": number_list = ['300033', '300032', '300031', '300030'] signal = ['1', '-1', '1', '-1'] pool = redis.ConnectionPool(host='redis-12143.c8.us-east-1-3.ec2.cloud.redislabs.com', port=12143, decode_responses=True, password='pkAWNdYWfbLLfNOfxTJinm9SO16eSJFx') r = redis.Redis(connection_pool=pool) for i in range(len(number_list)): value_new = str(number_list[i]) + ' ' + str(signal[i]) print(value_new) r.publish("chat", value_new) ``` ### 143. 如何高效的找到 redis 中的某個 KEY ```Python import redis con = redis.Redis() con.keys(pattern='key*') # *代表通配符 ``` ### 144. 基于 redis 實(shí)現(xiàn)先進(jìn)先出、后進(jìn)先出及優(yōu)先級隊(duì)列 ```Python class Zhan: def __init__(self,conn): self.conn = conn def push(self,val): self.conn.rpush('aaa',val) def pop(self): return self.conn.rpop('aaa') class Dui: def __init__(self,conn): self.conn = conn def push(self,val): self.conn.rpush('bbb',val) def get(self): return self.conn.lpop('bbb') class Xu: def __init__(self,conn): self.conn = conn def push(self,val,count): self.conn.zadd('ccc',val,count) def get(self): a = self.conn.zrange('ccc', 0, 0)[0] self.conn.zrem('ccc', a) return a ``` ### 145. redis 如何實(shí)現(xiàn)主從復(fù)制 在從服務(wù)器中配置 SLAVEOF 127.0.0.1 6380 # 主服務(wù)器 IP,端口 ### 146. 循環(huán)獲取 redis 中某個非常大的列表數(shù)據(jù) ```python def list_iter(name): """ 自定義redis列表增量迭代 :param name: redis中的name,即:迭代name對應(yīng)的列表 :return: yield 返回 列表元素 """ list_count = r.llen(name) for index in xrange(list_count): yield r.lindex(name, index) ``` ### 147. redis 中的 watch 的命令的作用 watch 用于在進(jìn)行事務(wù)操作的最后一步也就是在執(zhí)行 exec 之前對某個 key 進(jìn)行監(jiān)視,如果這個被監(jiān)視的 key 被改動,那么事務(wù)就被取消,否則事務(wù)正常執(zhí)行 ### 148. redis 分布式鎖 為 redis 集群設(shè)計(jì)的鎖,防止多個任務(wù)同時修改數(shù)據(jù)庫,其本質(zhì)就是為集群中的每個主機(jī)設(shè)置一個會超時的字符串,當(dāng)集群中有一半多的機(jī)器設(shè)置成功后就認(rèn)為加鎖成功,直至鎖過期或解鎖不會有第二個任務(wù)加鎖成功 ### 149. http 協(xié)議 超文本傳輸協(xié)議(HTTP,HyperText Transfer Protocol)是互聯(lián)網(wǎng)上應(yīng)用最為廣泛的一種網(wǎng)絡(luò)協(xié)議。HTTP 是一個客戶端和服務(wù)器端請求和應(yīng)答的標(biāo)準(zhǔn)??蛻舳耸墙K端用戶,服務(wù)器端是網(wǎng)站。一般由 HTTP 客戶端發(fā)起一個請求,建立一個到服務(wù)器指定端口(默認(rèn)是80端口)的 TCP 連接,HTTP 服務(wù)器則在那個端口監(jiān)聽客戶端發(fā)送過來的請求,并給與響應(yīng) ### 150. uwsgi,uWSGI 和 WSGI 的區(qū)別 WSGI:全稱是 Web Server Gateway Interface,是一種描述 web server 如何與 web application 通信的規(guī)范。django,flask 等都遵循該協(xié)議 uwsgi:是服務(wù)器和服務(wù)端應(yīng)用程序的一種協(xié)議,規(guī)定了怎么把請求轉(zhuǎn)發(fā)給應(yīng)用程序和返回; uwsgi 是一種線路協(xié)議而不是通信協(xié)議,在此常用于在 uWSGI 服務(wù)器與其他網(wǎng)絡(luò)服務(wù)器的數(shù)據(jù)通信 uWSGI:是一個 Web 服務(wù)器,它實(shí)現(xiàn)了 WSGI 協(xié)議、uwsgi、http 等協(xié)議。Nginx 中 HttpUwsgiModule 的作用是與 uWSGI 服務(wù)器進(jìn)行交換 ### 151. HTTP 狀態(tài)碼 1xx: 信息 2xx:成功 3xx:重定向 4xx:客戶端錯誤 5xx:服務(wù)器錯誤 ### 152. HTTP常見請求方式 GET,POST,PUT,DELETE,PATCH 等 ### 153. 響應(yīng)式布局 響應(yīng)式布局是 Ethan Marcotte 在2010年5月份提出的一個概念,簡而言之,就是一個網(wǎng)站能夠兼容多個終端——而不是為每個終端做一個特定的版本 ### 154. 實(shí)現(xiàn)一個簡單的 AJAX 請求 AJAX 是一種在無需重新加載整個網(wǎng)頁的情況下,能夠更新部分網(wǎng)頁的技術(shù)。 AJAX = 異步 JavaScript 和 XML ```JavaScript $(function(){ $('#send').click(function(){ $.ajax({ type: "GET", url: "test.json", data: {username:$("#username").val(), content:$("#content").val()}, dataType: "json", success: function(data){ $('#resText').empty(); //清空resText里面的所有內(nèi)容 var html = ''; $.each(data, function(commentIndex, comment){ html += '
' + comment['username'] + ':

'; }); $('#resText').html(html); } }); }); }); ``` ### 155. 同源策略 同源策略限制了從同一個源加載的文檔或腳本如何與來自另一個源的資源進(jìn)行交互。這是一個用于隔離潛在惡意文件的重要安全機(jī)制 如果兩個頁面的協(xié)議,端口(如果有指定)和主機(jī)都相同,則兩個頁面具有相同的源。我們也可以把它稱為“協(xié)議/主機(jī)/端口 tuple”,或簡單地叫做“tuple". ("tuple" ,“元”,是指一些事物組合在一起形成一個整體,比如(1,2)叫二元,(1,2,3)叫三元) ### 156. 什么是 CORS CORS 全稱是跨域資源共享(Cross-Origin Resource Sharing),是一種 AJAX 跨域請求資源的方式,支持現(xiàn)代瀏覽器 ### 157. 什么是 CSRF CSRF(Cross-site request forgery),中文名稱:跨站請求偽造,也被稱為:one click attack/session riding,縮寫為:CSRF/XSRF ### 158. 前端實(shí)現(xiàn)輪詢、長輪詢 輪詢 ```JavaScript var xhr = new XMLHttpRequest(); setInterval(function(){ xhr.open('GET','/user'); xhr.onreadystatechange = function(){ }; xhr.send(); },1000) ``` 長輪詢 ```JavaScript function ajax(){ var xhr = new XMLHttpRequest(); xhr.open('GET','/user'); xhr.onreadystatechange = function(){ ajax(); }; xhr.send(); } ``` ### 159. 簡述 MVC 和 MTV 所謂 MVC 就是把 web 應(yīng)用分為模型(M),控制器(C),視圖(V)三層,他們之間以一種插件似的,松耦合的方式連接在一起。 模型負(fù)責(zé)業(yè)務(wù)對象與數(shù)據(jù)庫的對象(ORM),視圖負(fù)責(zé)與用戶的交互(頁面),控制器(C)接受用戶的輸入調(diào)用模型和視圖完成用戶的請求 Django 中的 MTV 模式: Model(模型):負(fù)責(zé)業(yè)務(wù)對象與數(shù)據(jù)庫的對象(ORM) Template(模版):負(fù)責(zé)如何把頁面展示給用戶 View(視圖):負(fù)責(zé)業(yè)務(wù)邏輯,并在適當(dāng)?shù)臅r候調(diào)用 Model 和 Template,本質(zhì)上與 MVC 相同 ### 160. 接口的冪等性 接口冪等性就是用戶對于同一操作發(fā)起的一次請求或者多次請求的結(jié)果是一致的,不會因?yàn)槎啻吸c(diǎn)擊而產(chǎn)生了副作用 ### 161. Flask 框架的優(yōu)勢 簡潔,輕巧,擴(kuò)展性強(qiáng),自由度高 ### 162. 什么是 ORM ORM 的全稱是 Object Relational Mapping,即對象關(guān)系映射。它的實(shí)現(xiàn)思想就是將關(guān)系數(shù)據(jù)庫中表的數(shù)據(jù)映射成為對象,以對象的形式展現(xiàn),這樣開發(fā)人員就可以把對數(shù)據(jù)庫的操作轉(zhuǎn)化為對這些對象的操作 ### 163. PV、UV 的含義 PV:是(page view)訪問量,頁面瀏覽量或點(diǎn)擊量,衡量網(wǎng)站用戶訪問的網(wǎng)頁數(shù)量。在一定統(tǒng)計(jì)周期內(nèi)用戶每打開或刷新一個頁面就記錄1次,多次打開或刷新同一頁面則瀏覽量累計(jì) UV:是(Unique Visitor)獨(dú)立訪客,統(tǒng)計(jì)一段時間內(nèi)訪問某站點(diǎn)的用戶數(shù)(以cookie為依據(jù)) ### 164. supervisor 的作用 supervisor 管理進(jìn)程,是通過 fork/exec 的方式將這些被管理的進(jìn)程當(dāng)作 supervisor 的子進(jìn)程來啟動,所以我們只需要將要管理進(jìn)程的可執(zhí)行文件的路徑添加到 supervisor 的配置文件中即可 ### 165. 使用 ORM 和原生 SQL 的優(yōu)缺點(diǎn) 優(yōu)點(diǎn): - 方便的使用面向?qū)ο?,語句清晰 - 有效的防止 SQL 注入 - 方便動態(tài)構(gòu)造語句,對于不同的表的相同操作采用多態(tài)實(shí)現(xiàn)更優(yōu)雅; - 一定程度上方便重構(gòu)數(shù)據(jù)層 - 方便設(shè)置設(shè)置鉤子函數(shù) 缺點(diǎn): - 不太容易處理復(fù)雜查詢語句 - 性能較直接用 SQL 差 ### 166. 列舉一些 django 的內(nèi)置組件 Admin 組件:是對 model 中對應(yīng)的數(shù)據(jù)表進(jìn)行增刪改查提供的組件 model 組件:負(fù)責(zé)操作數(shù)據(jù)庫 form 組件:生成 HTML 代碼;數(shù)據(jù)有效性校驗(yàn);校驗(yàn)信息返回并展示 ModelForm 組件:用于數(shù)據(jù)庫操作,也可用于用戶請求的驗(yàn)證 ### 167. 列舉 Django 中執(zhí)行原生 sql 的方法 使用 execute 執(zhí)行自定義的 SQL 直接執(zhí)行 SQL 語句(類似于 pymysql 的用法) ```Python from django.db import connection cursor = connection.cursor() cursor.execute("SELECT DATE_FORMAT(create_time, '%Y-%m') FROM blog_article;") ret = cursor.fetchall() print(ret) ``` - 使用 extra 方法:queryset.extra(select={"key": "原生的SQL語句"}) - 使用 raw 方法 - 執(zhí)行原始 sql 并返回模型 - 依賴于 model 模型,多用于查詢操作 ### 168. cookie 和 session 的區(qū)別 cookie 是保存在瀏覽器端的鍵值對,可以用來做用戶認(rèn)證 sesseion 是將用戶的會話信息保存在服務(wù)端,key 值是隨機(jī)產(chǎn)生的字符串,value 值是 session 的內(nèi)容,依賴于 cookie 將每個用戶的隨機(jī)字符串保存到用戶瀏覽器中 ### 169. beautifulsoup 模塊的作用 BeautifulSoup 庫是解析、遍歷、維護(hù)“標(biāo)簽樹”的功能庫 ```Python url = "http://www.baidu.com/" request = requests.get(url) html = request.content soup = BeautifulSoup(html, "html.parser", from_encoding="utf-8") ``` ### 170. Selenium 模塊簡述 Selenium 是模擬操作瀏覽器的庫,可以根據(jù)我們的指令,讓瀏覽器自動加載頁面,獲取需要的數(shù)據(jù),甚至頁面截屏,或者判斷網(wǎng)站上某些動作是否發(fā)生等 ```Python from selenium import webdriver browser = webdriver.Chrome() browser.get('https://www.taobao.com') print(browser.page_source) # browser.page_source 是獲取網(wǎng)頁的全部 html browser.close() ``` 好了,這就是今天分享的全部內(nèi)容,如果喜歡就點(diǎn)個贊吧~ 后臺回復(fù)“面試題”獲取完整PDF版本 本文由[mdnice](https://mdnice.com/?platform=6)多平臺發(fā)布
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容