python基礎知識思維導圖
Python基礎:
說說你眼中的python( 2 )
-
談談你對python和其他語言的區別
1. python 中,變量是以內容為基准而不是像 c 中以變量名為基准; 2. python 中,一個變量可以以多個名稱訪問; 3. python 中,數字類型的值是不可變的; 4. python 中,編譯器會有一個小整數池的概念
- 談談你了了解的python種類以及相關特點
Python的種類: - Cpython:使用 C 解釋器來解釋擴展名:.pyc C解釋器 -> .pyc(字節碼) -> 機器碼 -> cpu - Jpython:使用 Java 解釋器 java 字節碼->機器碼 -> cpu - ironpython:使用C#解釋器 C# 字節碼 -> 機器碼 -> cpu PYPY:運行速度快,原理:解釋器->字節碼->編譯成機器碼->直接運行機器碼,用戶運行時直接使用機器碼,所以運行速度快。
- 字節碼和機器器碼的關系和區別?
- 機器碼(machine code),學名機器語言指令,有時也被稱為原生碼(Native Code),是電腦的CPU可直接解讀的數據。 - 通常意義上來理解的話,機器碼就是計算機可以直接執行,並且執行速度最快的代碼。 - 字節碼是一種中間狀態(中間碼)的二進制代碼(文件)。需要直譯器轉譯后才能成為機器碼。
- 為什么要學python
1. 編譯型語言:一次性,將全部的程序編譯成二進制文件,然后在運行。(c,c++ ,go) 優點:運行速度快。 缺點:開發效率低,不能跨平台。 2. 解釋型語言:當你的程序運行時,一行一行的解釋,並運行。(python , PHP) 優點:調試代碼很方便,開發效率高,並且可以跨平台。 缺點:運行速度慢。 3. 我對程序的定義是人可以讀懂,而機器剛好可以執行的一段代碼,注重於代碼的可讀性。 而Python的定位是“優雅”、“明確”、“簡單”,用它編寫的程序簡單易懂,這與我當初的想法不謀而合
- pep8規范
代碼編排 - 縮進。4個空格的縮進 - 每行最大長度79,換行可以使用反斜杠 - 類和top-level函數定義之間空兩行;類中的方法定義之間空一行;函數內邏輯無關段落之間空一行;其他地方盡量不要再空行。 文檔編排 - 模塊內容的順序:按標准、三方和自己編寫順序依次排放,之間空一行 - 不要在一句import中多個庫 空格的使用 注釋 文檔描述
- 123
- 123
py2與py3
- Python2和Python3的區別
1. 性能 - Py3.x性能比Py2.5慢15%,但還有很大的提升空間。 2.編碼 - Py3.X源碼文件默認使用utf-8編碼 3. 語法 - 去除print語句 - 關鍵詞加入as 和with,還有True,False,None - 刪除了raw_input,用input代替 - 新的metaclass語法 4. 字符串和字節串 - 字符串只有str一種類型 5.數據類型 - 只有一種整型——int - 新增了bytes類型 6.面向對象 - 容器類和迭代器類被ABCs化,所以cellections模塊里的類型比Py2.5多了很多 - 迭代器的next()方法改名為__next__(),並增加內置函數next(),用以調用迭代器的__next__()方法
- range和xrange的區別
兩者的區別是xrange返回的是一個可迭代的對象,range返回的則是一個列表. 同時效率更高,更快。 - 原因是實現的時候使用了 yield(此為python2.x回答,python3已刪除xrange)
- Python3和Python2中 int 和 long 的區別
int <= 32 位整數
long > 32 位整數 - 文件操作時:xreadlines和readlines的區別
xreadlines = 返回一個生成器對象, readlines = 遍歷文件所有行
- 123
- 123
進制轉換
- 二進制轉換成十進制:v = "0b1111011"
print(int(v,2)) # 可將任意進制數轉換成十進制數(數字,這是多少進制)
- 十進制轉換成二進制:v = 18
print(bin(v))
- 八進制轉換成十進制:v = "011"
print(int(v,8)) # 可將任意進制數轉換成十進制數(數字,這是多少進制)
- 十進制轉換成八進制:v = 30
print(oct(v))
- 十六進制轉換成十進制:v = "0x12"
print(int(v,16)) # 可將任意進制數轉換成十進制數(數字,這是多少進制)
- 123
運算符 ( 8 )
- 各類運算符詳解
- 各類運算符優先級
運算符 描述 ** 指數 (最高優先級) ~ + - 按位翻轉, 一元加號和減號 (最后兩個的方法名為 +@ 和 -@) * / % // 乘,除,取模和取整除 + - 加法減法 >> << 右移,左移運算符 & 位 'AND' ^ | 位運算符 <= < > >= 比較運算符 <> == != 等於運算符 = %= /= //= -= += *= **= 賦值運算符 is is not 身份運算符 in not in 成員運算符 and or not 邏輯運算符
- 求結果:2 & 5
按位與運算符:參與運算的兩個值,如果兩個相應位都為1,則該位的結果為1,否則為0 Python結果:0
- 求結果:2 ^ 5
按位異或運算符:當兩對應的二進位相異時,結果為1 Python結果:7
- 求結果:1 or 3
x or y 布爾"或" :如果 x 是 True,它返回 x 的值,否則它返回 y 的計算值。 Python結果:1
- 求結果:1 and 3
x and y 布爾"與" - : 如果 x 為 False,x and y 返回 False,否則它返回 y 的計算值。 python結果:>1
- 求結果:0 and 2 and 1
Python結果: 0
- 求結果:0 and 2 or 1
Python結果: 1
- 求結果:0 and 2 or 1 or 4
Python結果:1
- 求結果:0 or False and 1
Python結果:False
- 用⼀行代碼實現數值交換: a = 1 b = 2
b,a = a,b
- 123
數據結構( 2 )
- 基本的數據類型和方法都有哪些
列表:list - list.append(obj) # 在列表末尾添加新的對象 - list.count(obj) # 統計某個元素在列表中出現的次數 - list.extend(seq) # 在列表末尾一次性追加另一個序列中的多個值(用新列表擴展原來的列表) - list.index(obj) # 從列表中找出某個值第一個匹配項的索引位置 - list.insert(index, obj)# 將對象插入列表 - list.pop(obj=list[-1]) # 移除列表中的一個元素(默認最后一個元素),並且返回該元素的值 - list.remove(obj) # 移除列表中某個值的第一個匹配項 - list.reverse() # 反向列表中元素 - list.sort([func])# 對原列表進行排序 - list.clear() # 清空列表 - list.copy() # 復制列表 字典:dict - popitem() # 隨機返回並刪除字典中的一對鍵和值(一般刪除末尾對)。 - key in dict # 如果鍵在字典dict里返回true,否則返回false - radiansdict.copy() # 返回一個字典的淺復制 - radiansdict.keys() # 以列表返回一個字典所有的鍵 - radiansdict.items() # 以列表返回可遍歷的(鍵, 值) 元組數組 - radiansdict.clear() # 刪除字典內所有元素 - radiansdict.values() # 以列表返回字典中的所有值 - radiansdict.fromkeys() # 創建一個新字典,以序列seq中元素做字典的鍵,val為字典所有鍵對應的初始值 - radiansdict.update(dict2) # 把字典dict2的鍵/值對更新到dict里 - radiansdict.get(key, default=None) # 返回指定鍵的值,如果值不在字典中返回default值 - radiansdict.setdefault(key, default=None) # 和get()類似, 但如果鍵不存在於字典中,將會添加鍵並將值設為default - pop(key[,default]) # 刪除字典給定鍵 key 所對應的值,返回值為被刪除的值。key值必須給出。 否則,返回default值。 字符串:str - upper() # 轉換字符串中的小寫字母為大寫。 - title() # 返回"標題化"的字符串,就是說所有單詞都是以大寫開始,其余字母均為小寫(見 istitle())。 - lower() # 轉換字符串中所有大寫字符為小寫。 - rstrip() # 刪除字符串字符串末尾的空格. - lstrip() # 截掉字符串左邊的空格或指定字符。 - max(str) # 返回字符串 str 中最大的字母。 - min(str) # 返回字符串 str 中最小的字母。 - join(seq) # 以指定字符串作為分隔符,將 seq 中所有的元素(的字符串表示)合並為一個新的字符串 ... MySlef 整數:int - bit_length() # 查詢以二進制表示一個數字的值所需的位數 - int.from_bytes(bytes,byteorder) # 返回給定字節數組所表示的整數。 - int.to_bytes(length,byteorder) # 返回表示整數的字節數組。 元組:tuple - len(tuple) # 計算元組元素個數。 - max(tuple) # 返回元組中元素最大值。 - min(tuple) # 返回元組中元素最小值。 - tuple(seq) # 將列表轉換為元組。 集合:set - set1 = set({1, 2, 'barry'}) # 創建集合 - set2 = {1, 2, 'barry'} # 創建集合 - add # 將元素添加到集合中。如果元素已經存在,這不起作用。 - del set1 # 刪除集合- update # 迭代增加 - clear # 刪除此集合中的所有元素 - remove # 刪除一個元素 - pop # 隨機刪除一個元素 - issubset # 子集 - issuperset # 超集 - union # 並集。(| 或者 union) - difference # 差集。(- 或者 difference) - intersection # 交集。(& 或者 intersection) - isdisjoint # 如果兩個集合有一個空交點,則返回True - intersection_update # 用它自己和另一個交集更新一個集合。 - difference_update # 刪除另一個集合中本集合所擁有的所有元素 - symmetric_difference # 反交集。 (^ 或者 symmetric_difference) 浮點:float - is_integer # 如果浮點數是整數,則返回True collections:Python內建的一個集合模塊,提供了許多有用的集合類。 - Counter # 是一個簡單的計數器,例如,統計字符出現的個數: - OrderedDict # 可以實現一個FIFO(先進先出)的dict,當容量超出限制時,先刪除最早添加的Key: - deque # 是為了高效實現插入和刪除操作的雙向列表,適合用於隊列和棧: - defaultdict # 使用dict時,如果引用的Key不存在,就會拋出KeyError。如果希望key不存在時,返回一個默認值,就可以用defaultdict:
-
可變與不可變類型
可變: - list, - dict 不可變: -str, - int, - tuple, - float,
- 常⽤字符串格式化有哪些?
1.占位符% %d 表示那個位置是整數;%f 表示浮點數;%s 表示字符串 - print('Hello,%s' % 'Python') - print('Hello,%d%s%.2f' % (666, 'Python', 9.99)) # 打印:Hello,666Python10.00 2.format - print('{k} is {v}'.format(k='python', v='easy')) # 通過關鍵字 - print('{0} is {1}'.format('python', 'easy')) # 通過關鍵字
- 常用字符串格式化有哪些?
- 0 - "" - [] - {} - (,) - None
- *Python2和Python3有差嗎
Python2和Python3有差嗎
- Python2和Python3有差嗎
is和==的區別
- 123
- 123
- 123
- 123
- 123
- 123
函數( 9 )
- 函數參數傳遞的是什么? 引用、內存地址
# 默認參數盡量避免使用可變數據類型 # 默認參數只會被執行一次:第一次調用函數時,默認參數被初始化為【】,以后每次調用時都會使用已經初始化的【】。 >>> def func(a,a1 = []): #默認參數 ... a1.append(a) ... print(a1) >>> func() [1] >>> func() [1, 1] >>> func() [1, 1, 1] >>> func() [1, 1, 1, 1]
- 閉包函數
def foo(): m, n=3, 5 def bar(): a=4 return m+n+a return bar >>>bar = foo() >>>bar() 12 說明: bar在foo函數的代碼塊中定義。我們稱bar是foo的內部函數。
在bar的局部作用域中可以直接訪問foo局部作用域中定義的m、n變量。 簡單的說,這種內部函數可以使用外部函數變量的行為,就叫閉包。 - 閉包的意義與應用: 延遲計算; - 閉包的意義: 返回的函數對象,不僅僅是一個函數對象,在該函數外還包裹了一層作用域,這使得,該函數無論在何處調用,優先使用自己外層包裹的作用域 #應用領域:延遲計算(原來我們是傳參,現在我們是包起來) 裝飾器就是閉包函數的一種應用場景 - 談談你對閉包的理解?
說明: bar在foo函數的代碼塊中定義。我們稱bar是foo的內部函數。 在bar的局部作用域中可以直接訪問foo局部作用域中定義的m、n變量。 簡單的說,這種內部函數可以使用外部函數變量的行為,就叫閉包。 閉包的意義與應用: # 裝飾器就是閉包函數的一種應用場景 # 閉包的意義:返回的函數對象,不僅僅是一個函數對象,在該函數外還包裹了一層作用域,這使得,該函數無論在何處調用,優先使用自己外層包裹的作用域 # 應用領域:延遲計算(原來我們是傳參,現在我們是包起來) from urllib.request import urlopen def index(url): def get(): return urlopen(url).read() return get baidu=index('http://www.baidu.com') print(baidu().decode('utf-8'))
- 必會內置函數 - map
介紹: 會根據提供的函數對指定序列做映射。 第一個參數 function 以參數序列中的每一個元素調用 function 函數,返回包含每次 function 函數返回值的新列表。 語法: map(function, iterable, ...) - function -- 函數,有兩個參數 - iterable -- 一個或多個序列 應用示例: >>>def square(x) : # 計算平方數 ... return x ** 2 ... >>> map(square, [1,2,3,4,5]) # 計算列表各個元素的平方 [1, 4, 9, 16, 25] >>> map(lambda x: x ** 2, [1, 2, 3, 4, 5]) # 使用 lambda 匿名函數 [1, 4, 9, 16, 25] # 提供了兩個列表,對相同位置的列表數據進行相加 >>> map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10]) [3, 7, 11, 15, 19]
- 必會內置函數 - filter
介紹: 函數用於過濾序列,過濾掉不符合條件的元素,返回由符合條件元素組成的新列表。 該接收兩個參數,第一個為函數,第二個為序列,序列的每個元素作為參數傳遞給函數進行判,然后返回 True 或 False,最后將返回 True 的元素放到新列表中。 語法: filter(function, iterable) - function -- 判斷函數。 - iterable -- 可迭代對象。 應用示例1:過濾出列表中的所有奇數: def is_odd(n): return n % 2 == 1 newlist = filter(is_odd, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) print(newlist) >>>[1, 3, 5, 7, 9] 應用示例2:過濾出1~100中平方根是整數的數 import math def is_sqr(x): return math.sqrt(x) % 1 == 0 newlist = filter(is_sqr, range(1, 101)) print(newlist) >>>[1, 4, 9, 16, 25, 36, 49, 64, 81, 100] 應用示例3:filter相較於py2的區別 python2中返回的是過濾后的列表, 而python3中返回到是一個filter類 filter類實現了__iter__和__next__方法, 可以看成是一個迭代器, 有惰性運算的特性, 相對python2提升了性能, 可以節約內存。 a = filter(lambda x: x % 2 == 0, range(10)) print(a) >>><filter object at 0x000001CC57668518>
- 必會內置函數 - zip
介紹: 函數用於將可迭代的對象作為參數,將對象中對應的元素打包成一個個元組,然后返回由這些元組組成的列表。 如果各個迭代器的元素個數不一致,則返回列表長度與最短的對象相同,利用 * 號操作符,可以將元組解壓為列表。 語法: zip([iterable, ...]) - iterabl -- 一個或多個迭代器; 返回值: - 返回元組列表。 應用示例: >>>a = [1,2,3] >>> b = [4,5,6] >>> c = [4,5,6,7,8] >>> zipped = zip(a,b) # 打包為元組的列表 [(1, 4), (2, 5), (3, 6)] >>> zip(a,c) # 元素個數與最短的列表一致 [(1, 4), (2, 5), (3, 6)] >>> zip(*zipped) # 與 zip 相反,可理解為解壓,返回二維矩陣式 [(1, 2, 3), (4, 5, 6)]
- 必會內置函數 - isinstance
介紹: 函數來判斷一個對象是否是一個已知的類型,類似 type()。 語法: isinstance(object, classinfo) - object -- 實例對象。 - classinfo -- 可以是直接或間接類名、基本類型或者由它們組成的元組。 返回值: 如果對象的類型與參數二的類型(classinfo)相同則返回 True,否則返回 False。。 應用示例: >>>a = 2 >>> isinstance (a,int) True >>> isinstance (a,str) False >>> isinstance (a,(str,int,list)) # 是元組中的一個返回 True True
- isinstance() 與 type()的區別
介紹 1. type() 不會認為子類是一種父類類型,不考慮繼承關系。 2. isinstance() 會認為子類是一種父類類型,考慮繼承關系。 # 如果要判斷兩個類型是否相同推薦使用 isinstance()。 示例: class A: pass class B(A): pass isinstance(A(), A) # returns True type(A()) == A # returns True isinstance(B(), A) # returns True type(B()) == A # returns False
- pass的作用
- 1. 不做任何事情,一般用做占位語句。 - 2. pass是空語句,是為了保持程序結構的完整性。
- *args和**kwarg的作用
位置參數(positional argument) 關鍵詞參數(keyword argument) - *args表示任何多個無名參數,它本質是一個 tuple ; - **kwargs表示關鍵字參數,它本質上是一個 dict ; - 並且同時使用*args和**kwargs時,必須*args參數列要在**kwargs前。
- is和==的區別
- is 比較的是兩個實例對象是不是完全相同,它們是不是同一個對象,占用的內存地址是否相同。萊布尼茨說過:“世界上沒有兩片完全相同的葉子”,這個is正是這樣的比較,
比較是不是同一片葉子(即比較的id是否相同,這id類似於人的身份證標識)。 - == 比較的是兩個對象的內容是否相等,即內存地址可以不一樣,內容一樣就可以了。這里比較的並非是同一片葉子,可能葉子的種類或者脈絡相同就可以了。 默認會調用對象的 __eq__()方法。 - 123
- 123
- 123
函數的應用
- ⼀⾏代碼實現9*9乘法表
print('\n'.join([' '.join(['%s*%s=%-2s' % (j, i, i * j) for j in range(1, i + 1)]) for i in range(1, 10)]))
- 如何實現 “1,2,3” 變成 [‘1’,’2’,’3’]
- list("1,2,3".split(','))
- 如何實現[‘1’,’2’,’3’]變成[1,2,3]
[int(x) for x in ['1','2','3']]
- 如何⽤⼀⾏代碼⽣成[1,4,9,16,25,36,49,64,81,100]
[i*i for i in range(1,11)]
- ⼀行代碼實現刪除列表中重復的值
list(set([1, 2, 3, 4, 45, 1, 2, 343, 2, 2]))
-
請編寫一個函數實現將IP地址轉換成一個整數
如 10.3.9.12 轉換規則為:
10 00001010
3 00000011
9 00001001
12 00001100
再將以上二進制拼接起來計算十進制結果:00001010 00000011 00001001 00001100 = ?a = "10.3.9.12" def func(ip): Iplist = ip.split(".") # ['10', '3', '9', '12'] res = " " temp = [] for i in Iplist: # <class 'str'> i = int(i) # <class 'int'> i = bin(i)[2:] # <class 'str'> temp.append(i.rjust(8, "0")) # 右對齊,向左填充數據 res = res.join(temp) return res # 一行代碼實現: b = "".join([" ".join(str(bin(int(i))[2:]).rjust(8,"0") for i in a.split("."))]) print(func(a)) - "00001010 00000011 00001001 00001100"
- 用Python實現⼀個⼆分查找的函數 二分查找算法:
簡單的說,就是將一個列表先排序好,比如按照從小到大的順序排列好,當給定一個數據,比如3,查找3在列表中的位置時,可以先找到列表中間的數li[middle]和3進行比較,當它比3小時,那么3一定是在列表的右邊,反之,則3在列表的左邊,比如它比3小,則下次就可以只比較[middle+1, end]的數,繼續使用二分法,將它一分為二,直到找到3這個數返回或者列表全部遍歷完成(3不在列表中)
優點:效率高,時間復雜度為O(logN);
缺點:數據要是有序的,順序存儲。li = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] def search(someone, li): l = -1 h = len(li) while l + 1 != h: m = int((l + h) / 2) if li[m] < someone: l = m else: h = m p = h if p >= len(li) or li[p] != someone: print("元素不存在") else: str = "元素索引為%d" % p print(str) search(3, li) # 元素索引為2
- 1
- 1
- 1
- 1
- 1
- 1
- 請⽤代碼簡答實現stack
1. Stack() 創建一個新的空棧 2. push(item) 添加一個新的元素item到棧頂 3. pop() 彈出棧頂元素 4. peek() 返回棧頂元素 5. is_empty() 判斷棧是否為空 6. size() 返回棧的元素個數 class Stack(object): """棧""" def __init__(self): self.items = [] def is_empty(self): """判斷是否為空""" return self.items == [] def push(self, item): """加入元素""" self.items.append(item) def pop(self): """彈出元素""" return self.items.pop() def peek(self): """返回棧頂元素""" return self.items[len(self.items)-1] def size(self): """返回棧的大小""" return len(self.items) if __name__ == "__main__": stack = Stack() stack.push("hello") stack.push("world") stack.push("lcg") print stack.size() print stack.peek() print stack.pop() print stack.pop() print stack.pop()
- 內置函數:map、reduce、filter的用法和區別
map:遍歷序列,對序列中每個元素進行操作,最終獲取新的序列。 - 每個元素增加100: - li = [11, 22, 33] - new_list = map(lambda a: a + 100, li) - 兩個列表對應元素相加 - li = [11, 22, 33] - sl = [1, 2, 3, 4] - new_list = map(lambda a, b: a + b, li, sl) filter:對於序列中的元素進行篩選,最終獲取符合條件的序列。 - 獲取列表中大於12的所有元素集合 - li = [11, 22, 33] - new_list = filter(lambda arg: arg > 22, li) - # filter第一個參數為空,將獲取原來序列 reduce:對於序列內所有元素進行累計操作。 - 獲取序列所有元素的和 - li = [11, 22, 33] - result = reduce(lambda arg1, arg2: arg1 + arg2, li) - # reduce的第一個參數,函數必須要有兩個參數 - # reduce的第二個參數,要循環的序列 - # reduce的第三個參數,初始值
函數的騷操作( 8 )
- 手寫:三元運算符
>>> val = "aaa" if 1==1 else "bbb" >>> val 'aaa' >>>
- 手寫:lambda表達式
my_lambda = lambda arg : arg + 1
- 手寫:列表推導式
def func(x): return x+1 variable = [ func for num in range(10) if num == 2] func: # 列表生成元素表達式,可以是有返回值的函數或者 lambda 函數。 for num in range(10): # 迭代 range(10) 將 num 傳入 func 表達式中。 if num == 2: # 根據條件過濾哪些值可以。
- 手寫:列表推導式 + lambda表達式 :# 一行代碼寫出30以內所有能被3整除的數的平方:
# 錯誤示例:不能使用列表生成式 a = [lambda :i*i for i in range(31) if i%3 is 0] # 錯誤調用方式: # 每次只會返回最后一個被循環的range(30)! >>>a [. at 0x000002C97... ,>> a[0] . at 0x000002C977B96BF8> >>> a[0]() 900 # 正確示例:使用生成器迭代執行 # 注意括號! a = (lambda :i*i for i in range(31) if i%3 is 0) # 調用方式: >>> a.__iter__ <method-wrapper '__iter__' of generator object at 0x000002C977AF5938> >>> a.__iter__() at 0x000002C977AF5938> >>> a.__iter__().__next__ <method-wrapper '__next__' of generator object at 0x000002C977AF5938> >>> a.__iter__().__next__() . at 0x000002C977B8CF28> >>> a.__iter__().__next__()() 9
- 手寫字典推導式
# 推導式示例: >>> mcase = {'a': 10, 'b': 34} >>> mcase_frequency = {mcase[k]: k for k in mcase} >>> print(mcase_frequency) {10: 'a', 34: 'b'}
- 手寫:字典推導式:合並大小寫對應的value值,將k統一成小寫
# _._ >>> mcase = {'a': 10, b': 34, 'A': 7, 'Z': 3} >>> mcase_frequency = {k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0) for k in mcase.keys()} >>> print(mcase_frequency) {'a': 17, 'b': 34, 'z': 3}
- 手寫:集合推導式
# 集合推導式示例 >>> squared = {x**2 for x in [ i for i in range(-5,10) ]} >>> print(squared) {1, 4}
-
列表推導式list comprehension和生成器的優劣
1. 列表推導式是將所有的值一次性加載到內存中 2. 生成器是將列表推導式的[]改成(),不會將所有的值一次性加載到內存中,延遲計算,一次返回一個結果, 它不會一次生成所有的結果,這對大數據量處理,非常有用 # 生成器函數: 一個函數中包含了yield關鍵詞,那么這個函數就不是普通的函數,是一個生成器函數 # 調用生成器函數,不會立馬執行該函數里面的代碼, 而是會返回一個 生成器對象
python三神器( 7 )
- 生成器、迭代器、裝飾器、可迭代對象的區別
容器: - 是一系列元素的集合,str、list、set、dict、file、sockets對象都可以看作是容器,容器都可以被迭代(用在for,while等語句中),因此他們被稱為可迭代對象。 可迭代對象實現了__iter__方法,該方法返回一個迭代器對象。 迭代器: - 持有一個內部狀態的字段,用於記錄下次迭代返回值,它實現了__next__和__iter__方法,迭代器不會一次性把所有元素加載到內存,而是需要的時候才生成返回結果。 生成器: - 是一種特殊的迭代器,它的返回值不是通過return而是用yield。 裝飾器 - 在不改變原函數代碼的基礎上,在執行前后進行定制操作
- 生成器
- 生成器,一個函數內部存在yield關鍵字;v = 函數()。 應用場景: - range/xrange - py2: range(100000000),立即創建;xrange(100000000)生成器; - py3: range(100000000)生成器; - redis獲取值 conn = Redis(...) def hscan_iter(self, name, match=None, count=None): """ Make an iterator using the HSCAN command so that the client doesn't need to remember the cursor position. ``match`` allows for filtering the keys by pattern ``count`` allows for hint the minimum number of returns """ cursor = '0' while cursor != 0: # 去redis中獲取數據:12 # cursor,下一次取的位置 # data:本地獲取的12條數數據 cursor, data = self.hscan(name, cursor=cursor, match=match, count=count) for item in data.items(): yield item
- 迭代器
- 迭代器,內部實現__next__方法,幫助我們向后一個一個取值。
- 可迭代對象
可迭代對象介紹 - 一個類內部實現 __iter__ 方法且返回一個迭代器 - 實例: class Foo(object): def __iter__(self): return iter([11,22,33,44]) obj = Foo() - 應用場景: - wtform中對form對象進行循環時,顯示form中包含的所有字段。 - 列表、字典、元組
- 什么是裝飾器
裝飾器介紹 - 在不改變原函數代碼的基礎上,在執行前后進行定制操作 - 手寫 - 應用場景: - Flask : 路由、before_request、after_request - Django: csrf、緩存、內置用戶登錄認證 - functools:緩存、warper
- 手寫一個裝飾器
def waper(func): def inner(*args, **kwargs): res = func(*args, **kwargs) return res return inner
- 帶參數的裝飾器
def waper(func, x,y): print( int(x) + int(y) ) @functools.wapper # 保留原函數信息 def inner(*args, **kwargs): """blabla的一些注釋""" res = func(*args, **kwargs) return res return inner @wapper(1,2) def func(a): return a func(123)
面向對象 ( 10 )
- 談談你對面向對象的認識
- 簡單描述 :繼承、封裝、多態 - 系統描述 :先對代碼進行分類:按屬性進行划分(file,DB),按功能划分,將同一類方法分為一類。將方法中共同的參數封裝到對象中,把共用值封裝到對象中。 面向對象的私有字段: - python中一切皆對象 1. 封裝:對數據的,對對象的封裝。 2. 繼承:在類的基礎上進行二次開發,通過函數super() 或者"基類名.方法名() "的方式實現這一目的的。 3. 多態:同一個方法處於不同對象中,可以產生不同的結果 - 多態示例
# 鴨子模型
class A:
def send(self):
pass
class B:
def send(self):
pass
def func(arg):
arg.send()
obj = B()
func(obj) - 你知道哪些雙下划線方法
- 雙下划線: 1. __getattr__:反射 應用場景: - CBV - Django 配置文件 - wtforms中的Form()實例化中 將"_fields中的數據封裝到Form類中" 2. __mro__:定義解析類繼承的順序 應用場景:wtforms中 FormMeta中繼承的優先級 3. __dict__:用來存儲對象屬性的一個字典,其鍵為屬性名,值為屬性的值 - __dict__ 與 dir()的區別: 1. dir()是一個函數,返回值是list 2. dir用來尋找一個對象的所有屬性值,包括__dict__中的屬性,__dict__是dir()的子集 4. __new__ : - 當你繼承一些不可變的class時(比如int, str, tuple), 提供給你一個自定義這些類的實例化過程的途徑。 - 實現自定義 metaclass 應用場景: - wtforms 字段實例化時返回:不是StringField,而是UNboundField - rest_framework:many=Ture 中的序列化 - 單例模式 5. __call__:作用是使實例能夠像函數一樣被調用,同時不影響實例本身的生命周期, (__call__()不影響一個實例的構造和析構) 但是__call__()可以用來改變實例的內部成員。 __call__ 與 __init__的區別 應用場景: - FLask 請求的入口app.run() - 字段生成標簽時:字段.__str__ ==> 字段.__call__ ==> 插件.__call__ 6. __iter__: 迭代器為什么要一定實現__iter__方法(為什么要返回自身) 應用場景:wtforms中BaseForm中循環所有字段時自定義了__iter__方法
- metaclass的作用
- 作用:用於指定當前類事業那個類來創建 - 場景:在類創建之前定制的操作 示例:wtforms中對字段進行排序 -
super的作用:
子類繼承父類的方法,其繼承順序按照 __mro__來定義
- 新式類與經典類的區別
新式類跟經典類的差別主要是以下幾點: 1. 新式類對象可以直接通過__class__屬性獲取自身類型:type 2. 繼承搜索的順序發生了改變,經典類多繼承屬性搜索順序 : - 先深入繼承樹左側,再返回,開始找右側; - 新式類多繼承屬性搜索順序: 先水平搜索,然后再向上移動。 ps:(經典類深度優先,新式類廣度優先) 3. 新式類增加了__slots__內置屬性, 可以把實例屬性的種類鎖定到__slots__規定的范圍之中。 4. 新式類增加了__getattribute__方法 Python 2.x中默認都是經典類,只有顯式繼承了object才是新式類 Python 3.x中默認都是新式類,不必顯式的繼承object
- 深度優先和廣度優先是什么
python的類可以繼承多個類,python的類如果繼承了多個類,那么其尋找的方法有兩種: - 當類是經典類時:多繼承情況下,會按照深度優先的方式查找 - 當類是新式類時:多繼承情況下,會按照廣度優先的方式查找
簡單點說就是:經典類是縱向查找,新式類是橫向查找 - 什么是函數什么是方法?
from types import MethodType,FunctionType class func(object): def foo(self): print(1) Fun = func() print(type(func.foo)) >>> <class 'function'>
print(type(Fun.foo)) >>> <class 'method'>
print(isinstance(func.foo,FunctionType)) >>> True
print(isinstance(Fun.foo,MethodType)) >>> True 通過類去調用函數foo時,不需要傳self參數。此時foo為函數 如果通過對象Fun去調用foo時,對象自動傳參self。而foo則是一個方法 - 手寫三個使用不同方法實現的單例模式
單例模式:一個類只能有一個實例化對象
應用場景:Django中的admin組件中admin.site()就是由單例模式創建的,其中封裝了所有的表對象1. 文件導入 :import方法 # 作為python的模塊是天然的單例模式 class My_Singleton(object): def foo(self): pass my_singleton = My_Singleton() # to use from mysingleton import my_singleton my_singleton.foo() 2. 使用 __new__ 方法: --------------------------------(1. # 無法支持多線程 :)------------------------------ class Singleton(object): def __init__(self,name): self.name = name def __new__(cls, *args, **kwargs): if not hasattr(Singleton, "instance"): Singleton.instance = object.__new__(cls) return Singleton.instance # to use : obj0 = Singleton("alex") obj1 = Singleton("alex") obj2 = Singleton("alex") ----------------------------------(2. # 支持多線程:)--------------------------------- import threading class Singleton(object): instance_lock = threading.Lock() # 為線程加互斥鎖 def __init__(self): pass def __new__(cls, *args, **kwargs): if not hasattr(Singleton, "instance"): with Singleton.instance_lock: if not hasattr(Singleton, "instance"): Singleton.instance = object.__new__(cls) return Singleton.instance return Singleton.instance def task(): obj = Singleton() print(obj) for i in range(5): t = threading.Thread(target=task) t.start() 3. 使用類實現 --------------------------------(1. # 無法支持多線程 :)------------------------------ import threading class Singleton(object): def __init__(self): pass @classmethod def instance(cls, *args, **kwargs): if not hasattr(Singleton, "_instance"): Singleton._instance = Singleton(*args, **kwargs) return Singleton._instance # to use obj = Singleton.instance() obj2 = Singleton.instance() print(id(obj), id(obj2)) ----------------------------------(2. # 支持多線程:)--------------------------------- import time import threading class Singleton(object): _instance_lock = threading.Lock() def __init__(self): time.sleep(1) @classmethod def instance(cls, *args, **kwargs): if not hasattr(Singleton, "_instance"): with Singleton._instance_lock: if not hasattr(Singleton, "_instance"): Singleton._instance = Singleton(*args, **kwargs) return Singleton._instance # 第一次調用 def task(arg): obj = Singleton.instance() print(obj) for i in range(10): t = threading.Thread(target=task,args=[i,]) t.start() # 第二次調用 time.sleep(20) obj = Singleton.instance() obj2 = Singleton.instance() print(id(obj, id(obj2) 4. 基於metaclass --------------------------------------( 方法一 )-------------------------------------- # 創建對象 class SingletonType(type): def __call__(cls, *args, **kwargs): obj = super(SingletonType,cls).__call__(*args, **kwargs) #type類幫創建__new__和__init__並返回 return obj class Foo(metaclass=SingletonType): def __init__(self,name): self.name = name # to use obj = Foo("alex") print(id(obj1)) --------------------------------------( 方法二 )-------------------------------------- import threading class SingletonType(type): _instance_lock = threading.Lock() def __call__(cls, *args, **kwargs): if not hasattr(cls, "_instance"): with SingletonType._instance_lock: if not hasattr(cls, "_instance"): cls._instance = super(SingletonType,cls).__call__(*args, **kwargs) return cls._instance class Foo(metaclass=SingletonType): def __init__(self,name): self.name = name # to use obj1 = Foo('name') obj2 = Foo('name') print(id(obj1),id(obj2))
-
__new__
是一個靜態方法,而__init__
是一個實例方法.__new__
方法會返回一個創建的實例,而__init__
什么都不返回.- 只有在
__new__
返回一個cls的實例時后面的__init__
才能被調用. - 當創建一個新實例時調用
__new__
,初始化一個實例時用__init__
. - 繼承自object的新式類才有__new__
- __new__至少要有一個參數cls,代表當前類,此參數在實例化時由Python解釋器自動識別
- __new__必須要有返回值,返回實例化出來的實例,這點在自己實現__new__時要特別注意,
可以return父類(通過super(當前類名, cls))__new__出來的實例,或者直接是object的__new__出來的實例 - __init__有一個參數self,就是這個__new__返回的實例,__init__在__new__的基礎上可以完成一些其它初始化的動作,__init__不需要返回值
- 如果__new__創建的是當前類的實例,會自動調用__init__函數,通過return語句里面調用的__new__函數的第一個參數是cls來保證是當前類實例,
- 如果是其他類的類名,;那么實際創建返回的就是其他類的實例,其實就不會調用當前類的__init__函數,也不會調用其他類的__init__函數。
new與init的關系:
1. new優於init加載執行
2. 只能通過重寫new方法來自定義不可變的類對象:(int,str,tuple),--->init方法不行
3. 通過new方法可以實現單例模式
lass Singleton(object):
def __new__(cls):
# 關鍵在於這,每一次實例化的時候,我們都只會返回這同一個instance對象
if not hasattr(cls, 'instance'):
cls.instance = super(Singleton, cls).__new__(cls)
return cls.instance
obj1 = Singleton()
obj2 = Singleton()
obj1.attr1 = 'value1'
print obj1.attr1, obj2.attr1
print obj1 is obj2
- 知道有哪些類的雙下划線方法,並說明作用,返回值? https://www.zybuluo.com/kingwhite/note/136247
- 面向對象中super的作用?
用於執行子類繼承基類的方法
- 123
- 123
- 123
模塊 ( 26 )
-
你的常用模塊都有哪些 ( 1 )
copy : 用於深淺拷貝 os :與操作系統交互的一個接口 比如用來處理文件和目錄 random :隨機模塊 sys:負責程序與python解釋器的交互,提供了一系列的函數和變量,用於操控python的運行時環境。 json:序列化 re : 正則模塊 logging : 日志模塊 requests: 爬取數據 timeit : subprocess:與OS模塊相同,區別與異步提交命令不等待輸出。與OS模塊的區別
copy模塊 ( 1 )
- 淺拷貝與深拷貝的實現方式及區別,如果你來設計Deepcopy,如何實現
淺拷貝:只拷貝父對象,不會拷貝對象的內部的子對象(父對象不同,子對象進行引用,ID相同)>>> a = [1,[1,3],3] >>> import copy >>> b = copy.copy(a) >>> b [1, [1, 3], 3] >>> a[1].append(3) >>> b [1, [1, 3, 3], 3] <>>> a [1, [1, 3, 3], 3]
>>> a = [1,[1,2],3] >>> import copy >>> b = copy.deepcopy(a) >>> a[1].append(3) >>> b [1, [1, 2], 3] >>> a [1, [1, 2, 3], 3]
如何進行實現:
deepcopy優化版: class FiveCardStudInfo(roomai.abstract.AbstractInfo): public_state = None person_state = None def __deepcopy__(self, memodict={}): info = FiveCardStudInfo() info.public_state = self.public_state.__deepcopy__() info.public_state = self.person_state.__deepcopy__() return info
由於深拷貝需要維護一個 memo 用於記錄已經拷貝的對象,所以這也是它比較慢的原因
OS模塊 ( 3 )
- 你知道哪些OS模塊的方法
os.remove(‘path/filename’) # 刪除文件 os.rename(oldname, newname) # 重命名文件 os.walk() # 生成目錄樹下的所有文件名 os.chdir('dirname') # 改變目錄 os.getcwd() # 取得當前工作目錄 os.path.getsize() # 返回文件大小
-
創建、刪除文件
1. # 創建一個文件 2. open("chao.txt","w",encoding="utf-8") 3. import os #刪除文件 4. os.remove("chao.txt")
-
給出路徑找文件
--------------------------------( 方法一 )------------------------------ 使用os.walk: file-- 是你所要便利的目錄的地址, 返回的是一個三元組(root,dirs,files)。 root 所指的是當前正在遍歷的這個文件夾的本身的地址 dirs 是一個 list ,內容是該文件夾中所有的目錄的名字(不包括子目錄) files 同樣是 list , 內容是該文件夾中所有的文件(不包括子目錄) def open_2(file): for root, dirs , files in os.walk(file): print("ss",files) for filename in files: print(os.path.abspath(os.path.join(root, filename))) #返回絕對路徑 open_2("F:\搜索") --------------------------------( 方法二 )------------------------------ import os def open(files): for dir_file in os.listdir(files): # print("ss",dir_file) #遞歸獲取所有文件夾和文件 files_dir_file = os.path.join(files, dir_file) if os.path.isdir(files_dir_file): #是不是文件夾 open(files_dir_file) else: print(files_dir_file) open("F:\搜索") 並將下面的所有文件內容寫入到一個文件中 def open_2(file): for root, dirs , files in os.walk(file): for filename in files: with open(os.path.abspath(os.path.join(root, filename)), "r") as f: for i in f.readlines(): print(i) with open("./cao.txt","a",encoding="utf-8") as f2: f2.write(i) f2.write("\n") open_2("F:\搜索")
- 使用python打印路徑下的所有文件
# 方法一:(面試要求不使用os.walk) def print_directory_contents(sPath): import os for sChild in os.listdir(sPath): sChildPath = os.path.join(sPath, sChild) if os.path.isdir(sChildPath): print_directory_contents(sChildPath) else: print(sChildPath) # 方法二:(使用os.walk) def print_directory_contents(sPath): import os for root, _, filenames in os.walk(sPath): for filename in filenames: print(os.path.abspath(os.path.join(root, filename))) print_directory_contents('.')
-
如何使⽤python刪除⼀個⽂件
import os file = r'D:\test.txt' if os.path.exists(file): os.remove(file) print('delete success') else: print('no such file:%s' % file)
- 123
random模塊
- 如何⽣成⼀個隨機數?
import random print(random.random()) # 用於生成一個0到1的隨機符點數: 0 <= n < 1.0 print(random.randint(1, 1000)) # 用於生成一個指定范圍內的整數
- 123
- 123
co
re模塊 ( 4 )
- re模塊的基本方法:
. 匹配除換行符以外的任意字符 \w 匹配字母或數字或下划線 \s 匹配任意的空白符 \d 匹配數字 \n 匹配一個換行符 \t 匹配一個制表符 \b 匹配一個單詞的結尾 ^ 匹配字符串的開始 $ 匹配字符串的結尾 \W 匹配非字母或數字或下划線 \D 匹配非數字 \S 匹配非空白符 a|b 匹配字符a或字符b () 匹配括號內的表達式,也表示一個組 [...] 匹配字符組中的字符 [^...] 匹配除了字符組中字符的所有字符 用法說明 * 重復零次或更多次 + 重復一次或更多次 ? 重復零次或一次 {n} 重復n次 {n,} 重復n次或更多次 {n,m} 重復n到m次
-
手寫正則
匹配郵箱:
- [\w!#$%&'*+/=?^_`{|}~-]+(?:\.[\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])? - \w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}
匹配URL地址: - [a-zA-z]+://[^\s]*
匹配國內手機號: - \d{3}\d{8}|\d{4}\{7,8}
匹配身份證號碼: - ^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$ -
match和search的區別
- re.match :只匹配字符串的開始,如果字符串開始不符合正則表達式,則匹配失敗,函數返回None; - re.search:匹配整個字符串,直到找到一個匹配。
import re s = "fnfffidvvgf" m = re.match("fi",s) print(m)
>>> #None s = re.search("fi",s).group() print(s)
>>> #fi - 貪婪匹配與非貪婪匹配
- 匹配0次或多次 <.*> - 非貪婪匹配:匹配0次或1次 <.?>
functools模塊
- 是否使⽤過functools中的函數?其作⽤是什么?
# 用於修復裝飾器 import functools def deco(func): @functools.wraps(func) # 加在最內層函數正上方 def wrapper(*args, **kwargs): return func(*args, **kwargs) return wrapper @deco def index(): '''哈哈哈哈''' x = 10 print('from index') print(index.__name__) print(index.__doc__) # 加@functools.wraps # index # 哈哈哈哈 # 不加@functools.wraps # wrapper # None
- reduce
在Python 3里,reduce()函數已經被從全局名字空間里移除了,它現在被放置在fucntools模塊里 用的話要 先引入: >>> from functools import reduce reduce函數,reduce函數會對參數序列中元素進行累積。 reduce函數的定義: reduce(function, sequence[, initial]) -> value function參數是一個有兩個參數的函數,reduce依次從sequence中取一個元素,和上一次調用function的結果做參數再次調用function。 第一次調用function時,如果提供initial參數,會以sequence中的第一個元素和initial作為參數調用function,否則會以序列sequence中的前兩個元素做參數調用function。 reduce(lambda x, y: x + y, [2, 3, 4, 5, 6], 1) 結果為21( (((((1+2)+3)+4)+5)+6) ) reduce(lambda x, y: x + y, [2, 3, 4, 5, 6]) 結果為20
- 123
其他函數
- 如何判斷是函數還是方法
from types import FunctionType from types import MethodType print(isinstance(obj.func, FunctionType)) # False print(isinstance(obj.func, MethodType)) # True
其他
-
設計模式分為三大類: 創建型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。 結構型模式,共七種:適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。 行為型模式,共十一種:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式。 其實還有兩類:並發型模式和線程池模式。
-
編碼和解碼了解過么
-
什么是裝飾器,如果想在函數之后進行裝飾應該怎么做
一個函數,想在運行時動態的增加功能,又不會改動函數本身的代碼 -
使用裝飾器的單例模式和使用其他方法的單例,在后續使用中有什么區別
-
引⽤計數機制的優點: 1、簡單 2、實時性:⼀旦沒有引⽤,內存就直接釋放了。不⽤像其他機制等到特定時機。實時性還帶來⼀個好處:處理回收內存的時間分攤到了平時。 引⽤計數機制的缺點: 1、維護引⽤計數 2、消耗資源循環引⽤ list1 = []; list2 =[] list1.append(list2); list2.append(list1) 3、list1與list2相互引⽤,如果不存在其他對象對他們的引用,list1與list2的引用計數也仍然1,所占⽤的內存永遠無法被回收,這將是致命的。 對於如今的強⼤硬件,缺點1尚可接受,但是循環引⽤導致內存泄露,注定python會將引⼊新的回收機制。(分代收集) 有三種情況會觸發垃圾回收: 1、當 gc 模塊的計數器達到閥值的時候,自動回收垃圾 2、調⽤ gc.collect(),手動回收垃圾 3、程序退出的時候,python解釋器來回收垃圾
-
多線程可以共享全局變量,多進程不能。多線程中,所有子線程的進程號相同;多進程中,不同的子進程進程號不同。
python的threading和multiprocessing模塊 -
進程通信有哪幾種方式
無名管道( pipe ): - 管道是一種半雙工的通信方式,數據只能單向流動,而且只能在具有親緣關系的進程間使用。進程的親緣關系通常是指父子進程關系。
高級管道(popen): - 將另一個程序當做一個新的進程在當前程序進程中啟動,則它算是當前程序的子進程,這種方式我們成為高級管道方式。
有名管道(named pipe) : - 有名管道也是半雙工的通信方式,但是它允許無親緣關系進程間的通信。
消息隊列( message queue ) : - 消息隊列是由消息的鏈表,存放在內核中並由消息隊列標識符標識。消息隊列克服了信號傳遞信息少、管道只能承載無格式字節流以及緩沖區大小受限等缺點。
信號量( semophore ) :- 信號量是一個計數器,可以用來控制多個進程對共享資源的訪問。它常作為一種鎖機制,防止某進程正在訪問共享資源時,其他進程也訪問該資源。因此,主要作為進程間以及同一進程內不同線程之間的同步手段。
信號 ( sinal ) : - 信號是一種比較復雜的通信方式,用於通知接收進程某個事件已經發生。
共享內存( shared memory ) : - 共享內存就是映射一段能被其他進程所訪問的內存,這段共享內存由一個進程創建,但多個進程都可以訪問。共享內存是最快的 IPC 方式,它是針對其他進程間通信方式運行效率低而專門設計的。它往往與其他通信機制,如信號兩,配合使用,來實現進程間的同步和通信。
套接字( socket ):- 套解口也是一種進程間通信機制,與其他通信機制不同的是,它可用於不同機器間的進程通信。 - 寫出將IP地址127.0.0.1轉換為32位二進制和數的函數
- 單向鏈表和雙向鏈表
- 寫出將IPv4地址轉換為IPv6的函數
- 面向對象的應用場景
# 需要傳過多的參數: class Foo(object): def __init__(self, a1, a2, a3, ... , an): self.a1 = a1 self.a2 = a2 ... def index(self): pass # 給了一些值,對數據進行加工:Django的自定義分頁 class Foo(object): def __init__(self, a1, a2, a3, ... , an): self.a1 = a1 self.a2 = a2 ... def index(self): return self.a1 + self.a2
- QAQ
RESTful ( 12 )
- 談談你對rest api的認識
- 用過哪些rest 框架
- Django的rest_framework - 原生CBV
- 不使用rest_framework
利用Django的CBV來實現RESTful,使開發者代碼會多一些。 通過使用rest_framework框架提高開發效率。
- 這個框架使用最多的是什么?
Serializers
用戶登錄認證
分頁
頻率等 - rest_framework視圖中你都用過哪些基類
GenericAPIView
- !rest_framework的GenericAPIView都繼承過哪些類
- rest_framework框架有哪些優點?
- rest_framework都有哪些組件?
-
- 路由:自動幫助開發者快速為一個視圖創建四個URL - 版本 - URL - GET - 請求頭 - 認證 - !認證的流程是什么 - 權限 - 權限能不能在中間件做 - 訪問頻率的控制 - 視圖 - 解析器:根據Content-Type請求體中的格式數據進行處理。request,data - 分頁 - 序列化 - 序列化 - source - 定義方法 - 請求的數據格式校驗 - 渲染器
- 頻率組件是怎么做的
- 限制的頻率是多少?
1分鍾:60-80次/每秒鍾1-2次
- 什么是冪等性?
冪等性: 一個接口進行一次或多次訪問,對資源不造成影響(是否會對資源造成二次傷害),那么我們就認為這個接口具有冪等性。
例如:GET:
putdelete請求非冪等性: 例如:請求等 具有爭議性的請求: patch:
- 0
- 2
算法排序部分(9)
- 手寫快排;堆排;幾種常用排序的算法復雜度是多少;快排平均復雜度多少,最壞情況如何優化;
- 手寫:已知一個長度n的無序列表,元素均是數字,要求把所有間隔為d的組合找出來,你寫的解法算法復雜度多少;
- 手寫:一個列表A=[A1,A2,…,An],要求把列表中所有的組合情況打印出來;
- 手寫:用一行python寫出1+2+3+…+10**8 ;
- 手寫python:用遞歸的方式判斷字符串是否為回文;
- 單向鏈表長度未知,如何判斷其中是否有環;
- 單向鏈表如何使用快速排序算法進行排序;
- 手寫:一個長度n的無序數字元素列表,如何求中位數,如何盡快的估算中位數,你的算法復雜度是多少;
- 如何遍歷一個內部未知的文件夾(兩種樹的優先遍歷方式)
網絡基礎部分(11)
- TCP/IP分別在模型的哪一層;
- socket長連接是什么意思;
- select和epoll你了解么,區別在哪;
- TCP UDP區別;三次握手四次揮手講一下;
# TCP三次握手 # 1. 客戶 --> 服務:SYN=1(發起新連接) seq = J(隨機值) # 2. 服務 --> 客戶: # SYN=1, # ACK=1(確認接受這次連接請求), # ack=J+1(從廣播的眾多連接請求響應中中發現針對自己的響應,網絡是廣播的) # seq = K # 3. 客戶 --> 服務 # ACK=1(我知道你接受我了) # ack=K+1(服務端從眾多的連接連理響應中發現針對自己的) # 當然,第三次握手消息,服務端也可能沒有接收到,但不可能兩邊一直這樣ACK下 # 去。但是還可以基於超時時間,重新發起連接請求。
- TIME_WAIT過多是因為什么;
- http一次連接的全過程:你來說下從用戶發起request——到用戶接收到response時的全過程;
- http連接方式。get和post的區別,你還了解其他的方式么;
- restful你知道么;
- 狀態碼你知道多少,比如200/403/404/504等等;# 更多信息跳轉w3
- TCP/UDP
- socket連接和HTTP連接的區別
- Q^Q
HTTP部分( 11 )
- 常用的HTTP方法有哪些?
GET: 用於請求訪問已經被URI(統一資源標識符)識別的資源,可以通過URL傳參給服務器 POST:用於傳輸信息給服務器,主要功能與GET方法類似,但一般推薦使用POST方式。 PUT: 傳輸文件,報文主體中包含文件內容,保存到對應URI位置。 HEAD: 獲得報文首部,與GET方法類似,只是不返回報文主體,一般用於驗證URI是否有效。 DELETE:刪除文件,與PUT方法相反,刪除對應URI位置的文件。 OPTIONS:查詢相應URI支持的HTTP方法。
- GET方法與POST方法的區別
區別一: - get重點在從服務器上獲取資源,post重點在向服務器發送數據; 區別二: - get傳輸數據是通過URL請求,以field(字段)= value的形式,置於URL后,並用"?"連接,多個請求數據間用"&"連接,
如http://127.0.0.1/Test/login.action?name=admin&password=admin,這個過程用戶是可見的; - post傳輸數據通過Http的post機制,將字段與對應值封存在請求實體中發送給服務器,這個過程對用戶是不可見的; 區別三: - Get傳輸的數據量小,因為受URL長度限制,但效率較高; - Post可以傳輸大量數據,所以上傳文件時只能用Post方式; 區別四: - get是不安全的,因為URL是可見的,可能會泄露私密信息,如密碼等; - post較get安全性較高; 區別五: - get方式只能支持ASCII字符,向服務器傳的中文字符可能會亂碼。 - post支持標准字符集,可以正確傳遞中文字符。 - HTTP請求報文與響應報文格式
請求報文包含三部分: - 請求行:包含請求方法、URI、HTTP版本信息 - 請求首部字段 - 請求內容實體 響應報文包含三部分: - 狀態行:包含HTTP版本、狀態碼、狀態碼的原因短語 - 響應首部字段 - 響應內容實體
- 常見的HTTP相應狀態碼
200:請求被正常處理 204:請求被受理但沒有資源可以返回 206:客戶端只是請求資源的一部分,服務器只對請求的部分資源執行GET方法,相應報文中通過Content-Range指定范圍的資源。 301:永久性重定向 302:臨時重定向 303:與302狀態碼有相似功能,只是它希望客戶端在請求一個URI的時候,能通過GET方法重定向到另一個URI上 304:發送附帶條件的請求時,條件不滿足時返回,與重定向無關 307:臨時重定向,與302類似,只是強制要求使用POST方法 400:請求報文語法有誤,服務器無法識別 401:請求需要認證 403:請求的對應資源禁止被訪問 404:服務器無法找到對應資源 500:服務器內部錯誤 503:服務器正忙
- HTTP1.1版本新特性
1. 默認持久連接節省通信量,只要客戶端服務端任意一端沒有明確提出斷開TCP連接,就一直保持連接,可以發送多次HTTP請求 2. 管線化,客戶端可以同時發出多個HTTP請求,而不用一個個等待響應
3. 斷點續傳原理 - 常見HTTP首部字段
1. 通用首部字段(請求報文與響應報文都會使用的首部字段) - Date:創建報文時間 - Connection:連接的管理 - Cache-Control:緩存的控制 - Transfer-Encoding:報文主體的傳輸編碼方式 2. 請求首部字段(請求報文會使用的首部字段) - Host:請求資源所在服務器 - Accept:可處理的媒體類型 - Accept-Charset:可接收的字符集 - Accept-Encoding:可接受的內容編碼 - Accept-Language:可接受的自然語言 3. 響應首部字段(響應報文會使用的首部字段) - Accept-Ranges:可接受的字節范圍 - Location:令客戶端重新定向到的URI - Server:HTTP服務器的安裝信息 4. 實體首部字段(請求報文與響應報文的的實體部分使用的首部字段) - Allow:資源可支持的HTTP方法 - Content-Type:實體主類的類型 - Content-Encoding:實體主體適用的編碼方式 - Content-Language:實體主體的自然語言 - Content-Length:實體主體的的字節數 - Content-Range:實體主體的位置范圍,一般用於發出部分請求時使用
- HTTP與HTTPS的區別
對傳輸內容加密
端口: HTTP:80 HTTPS:443
自定義證書 - HTTP的缺點與HTTPS
1. 通信使用明文不加密,內容可能被竊聽 2. 不驗證通信方身份,可能遭到偽裝 3. 無法驗證報文完整性,可能被篡改 # HTTPS就是HTTP加上加密處理(一般是SSL安全通信線路)+認證+完整性保護
- HTTP優化
-
從瀏覽器輸入域名網址到看到頁面都發生了什么
1.瀏覽器向DNS服務器詢問域名對應的IP地址 2.得到域名對應的IP地址后,組裝HTTP請求報文 3.由TCP協議將請求報文分割成多個報文段,可靠的傳給對方 4.由IP協議搜索對方地址,並傳送報文,此過程可能經過多個路由器 5.服務器端的TCP從對方接收到報文 6.服務器端的HTTP解析請求報文,處理並生成響應報文 7.按照相反的順序,將響應報文發回給瀏覽器 8.瀏覽器根據響應報文解析數據(一般為html文檔),並渲染頁面,文檔中也很可能引用了其他資源,這些資源同樣使用HTTP協議想服務器請求
- 什么是websocket
websocket是一種類似HTTP的協議: - 讓C/S創建鏈接不斷開,以此可以完成:S向C主動推送消息 - websocket協議額外做的一些前提操作: - 握手,連接前進行校驗 - 發送數據,進行加密 websocket的本質 ... 應用場景: 5月17日13:19:13,141 - Django: channel - Flask : gevent-websocket - tornado:內置
QAQ
- q^q
數據庫部分( 20 )
- MySQL有幾種引擎:查詢表數據練習題
InnoDB: - 支持事務 - 行鎖/表鎖 - 表鎖: - select * from tb for update - 行鎖: - select * from tb where id=2 for update; MyISAM: - 全文索引< - 表鎖 - 查詢速度快 - 表鎖語句: - select * from tb for update;
- Innodb是索引和數據是緊密捆綁的,沒有使用壓縮;
- 而MyISAM的索引和數據是分開的,並且索引是有壓縮的,內存使用率就對應提高了不少,能加載更多索引,因此,用MyISAM可節省不少硬盤空間。 - 數據庫中函數用過哪些?
聚合函數:max/sum/min/avg
時間格式化:date_format
字符串拼接:concat - 索引有哪幾種?區別是什么?
單列:B+樹/哈希索引 --> 查詢速度快更新速度慢 - 普通索引 :加速查找 - 唯一索引 :加速查詢 + 約束(不能重復) - 主鍵索引 :加速查詢 + 約束(不能重復) + 不能為空 - 全文索引 : 多列:遵循最左前綴規則 - 聯合索引 : - 聯合唯一索引 : 其他: - 索引合並 :利用多個單例索引查詢 - 覆蓋索引 :在索引表中就能將想要的數據查詢到 - 組合索引遵循最左前綴規則 如果組合索引為:(name,email) name and email -- 使用索引 name -- 使用索引 email -- 不使用索引
- 慢日志如何開啟?
slow_query_log = OFF # 是否開啟慢日志記錄 long_query_time = 2 # 時間限制,超過此時間,則記錄 slow_query_log_file = /usr/slow.log # 日志文件 log_queries_not_using_indexes = OFF # 為使用索引的搜索是否記錄
- MySQL鎖有幾種;死鎖是怎么產生的;
mysql鎖能在並發情況下的mysql進行更好的優化 MySQL有三種鎖的級別:頁級、表級、行級,這3種鎖的特性可大致歸納如下: 表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖沖突的概率最高,並發度最低。 行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖沖突的概率最低,並發度也最高。 頁面鎖:開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,並發度一般。
- 為何,以及如何分區、分表;
- MySQL的char varchar text的區別;
- select的幾種區別
1. select 1與select * 的區別: “selelct 常量 from 表名” 對應所有行,返回的永遠只有一個值,即常量 ,所以一般只用來判斷是否有表記錄; 而“select * from 表名” 是返回所有行的所有列。 性能上的差異,關鍵看from和where子句。如果where條件中可以通過索引,那顯然 “selelct 常量 from 表名” 的性能比“select * from 表名” 好。 2. select count(1) 與select count(*) 的區別 : 性能上的差異,跟表結構有關系: 如果表中沒有主鍵,那么count(1)比count(*)快 如果有主鍵,那么count(主鍵,聯合主鍵)比count(*)快 如果表中只有一個字段,count(*)最快 3. select sum(1)的使用: select count(*)返回所有滿足條件的記錄數,此時等同於select sum(1) 但是sum()可以傳任意數字,負數、浮點數都可以,返回的值是傳入值n*滿足條件記錄數m
- 存儲過程和函數的區別
函數: - 參數 - 返回值:return 存儲過程: - 參數 - 返回值:out/inout - 返回結果集:select * from tb;
- 什么是視圖
虛擬表 --> 通過SQL幫助我們實時查詢數據
- 什么是觸發器
在對表進行 增刪改查 前后定義一些SQL操作
- 對前端產生的分頁是如何處理的
- 數據庫分頁 存在問題: 查詢的頁面數越大,速度就會越慢,這是因為每次數據庫都會從第一條開始掃描 selsct * from tb limit 3 offset 5 models.User.object.all()[0:10] 解決方法: 根據業務場景來說: 1.如果業務對歷史數據不要求的話,就顯示一定的頁數,就可以避免這樣的問題 2.記錄當前頁數據id的最大最小值,根據記錄的id和需要查詢的范圍來定。 但是在url上面會有page的值,如果用戶隨意改url上的頁碼的值的時候,可以參考restfromwork的分頁來做,
對當前的url進行加密,加密之后它里面就帶了當前頁的最大和最小id,解密出來之后就可以直接拿來用,而且用戶也沒有辦法在url上隨便修改了 - 了解join么,有幾種,有何區別,A LEFT JOIN B,查詢的結果中,B沒有的那部分是如何顯示的(NULL);
- 寫出SQL語句:獲取一條name="alex"的數據
select * from tb name='alex' limit 1
- BTree索引和hash索引的區別(在磁盤結構上的區別);
- 手寫:如何對查詢命令進行優化;
1. 不用 select * 2. 固定長度字段列,往前放 3. char 和 varchar 4. 固定數據放入內存 choice 5. 數據庫讀寫分離 6. 分庫:當數據庫中表過多,將表分到不同的數據庫() 7. 分表: - 水平分表:將某些列拆分到另一張表:博客+博客詳細 - 垂直分表:將一些歷史信息分到另一張表中:歷史賬單 8. 緩存:利用redis、memcache進行存儲 ps:當緩存宕機,如果沒有進行持久化則將所有請求轉接MySQL,
而MySQL承受不了壓力時會造成無法啟動 9. 其它 - 慢日志 - 執行計划 10. 分頁 - NoSQL了解么,和關系數據庫的區別;
- redis有幾種常用存儲類型;
- 樂觀鎖和悲觀鎖
- 觸發器是什么?
- QAQ
Linux部分( 4 )
- 講一下你常用的Linux/git命令和作用;
- 查看當前進程是用什么命令,除了文件相關的操作外,你平時還有什么操作命令;
- Apache和Nginx的區別
- 介紹下中間人攻擊:
# 中間人攻擊(Man-in-the-middle attack,通常縮寫為MITM)是指攻擊者與通訊的兩端分別創建獨立的聯系,並交換其所收到的數據, 使通訊的兩端認為他們正在通過一個私密的連接與對方直接對話,但事實上整個會話都被攻擊者完全控制。
- 1
前端部分( 2 )
- 你用過什么框架和類庫
- jQuery - BootStrap - Vue.js、React、Angular.js
- 什么是響應式布局
通過瀏覽器和設備分辨率的改變做出相應的變化
本質是通過 @media屬性來完成:
<style>
body{
margin:0;}
.pg-header{
background-color:red;
height: 48px;}
@media( min-width: 768px ){
.pg-header{background-color: green;}}
@media( min-width: 992px ){
.pg-header{background-color: pink;}}
</style>
django項目部分( 19 )
- 簡單的介紹下你在公司的項目,不管是不是后端相關的,主要是要體現出你干了什么;
- 你在項目中遇到最難的部分是什么,你是怎么解決的;
- Django和Flask框架的區別
Django: - 內置很多組件: - ORM、admin、Form、ModelForm、中間件、信號、緩存、csrf等 Flask: - 一個輕量級框架內置組件少,可擴展很多第三方組件: - flask-session、flask-script、flask-redis、flask-flask-migrate - flask-SQLAlchemy、wtforms、blinker 兩個框架都是基於wsgi協議實現的,默認使用的wsgi模塊不一樣, 還有一個顯著的特點:處理請求的方式不一樣 - Django:通過將請求封裝成request對象,再通過參數進行傳遞 - flask: 通過上下文管理實現 延伸: - Django組件 - flask組件、用途 - wsgi - 上下文管理
- MVC / MTV;
- Django請求生命周期
1. wsgi:創建socket服務端,用於接收用戶請求並對請求進行初次封裝
2. 中間件:對所有請求到來之前,響應之前定制一些操作
3. 路由: 匹配路由,在url和視圖函數對應關系中,根據當前請求url找到相應的函數
4. 視圖函數:執行視圖函數,業務處理【通過ORM去數據庫中獲取數據,再去拿到模板,然后將數據和模板進行渲染】
5. 在經過中間件
6. 通過wsgi將響應返回給用戶 - 什么是wsgi
是web服務網關接口,是一套協議。以下模塊實現了wsgi協議: - wsgiref :性能低,易配置 - werkzurg - uwsgi 以上模塊本質:實現socket監聽請求,獲取請求后將數據封裝,然后交給web框架處理
詳解:
本質是編寫了socket服務端,用來監聽用戶的請求,如果有請求到來,則將請求進行一次封裝然后將【請求】交給web框架來進行下一步處理 - 中間件是干嘛的;
所有請求都要穿過中間件: - 對所有的請求進行批量處理 - 在視圖函數執行之前后進行一些自定義操作。
- 你用中間件做過什么;
- 解決cors跨域請求 - csrf - csrf的本質: - 用戶先發送get獲取csrf token:Form表單中一個隱藏的標簽 + cookie - 發起post請求時,需要攜帶之前發送給用戶的csrf token; - 在中間件的process_view 方法中進行校驗
- 中間件中有幾個方法分別是什么;(五個方法)
- process_request(self,request) - process_view(self, request, callback, callback_args, callback_kwargs) - process_template_response(self,request,response) # 當視圖函數的返回值對象中有render方法時,該方法才會被調用 - process_exception(self, request, exception) - process_response(self, request, response)
中間件的執行流程: 1 請求先執行所有中間件的process_request,然后做路由匹配,找到函數不執行。 2 再執行所有的process_view,在執行視圖函數。 3 再執行process_response 4 如果程序報錯執行process_exception 5 如果程序有render方法則執行process_template_response - 中間件的應用:
# 為什么要在中間件用這些: - 一些內置組件上的應用: - csrf - session 緩存 - 用戶登錄校驗 # 如果不使用就需要為每個函數添加裝飾器,太過繁瑣。 - 權限處理 # 用戶登錄后將權限放到session中,然后再每次請求時都需要判斷當前用戶是否有權訪問當前url,這些檢查的東西可以放到中間件中統一處理。 - session - 跨域: - 前后端分離時,本地測試開發時使用的
- CSRF原理
目標:防止用戶直接向服務端發起POST請求。 方案:先發送GET請求時,將token保存到:cookie、Form表單中(隱藏的input標簽),以后再發送請求時只要攜帶過來即可。 問題:如果想后台發送POST請求? form表單提交: <form method="POST"> {% csrf_token %} <input type='text' name='user' /> <input type='submit' /> </form> ajax提交: $.ajax({ url:'/index', type:'POST', data:{csrfmiddlewaretoken:'{{ csrf_token }}',name:'alex'} }) 前提:引入jquery + 引入jquery.cookie $.ajax({ url: 'xx', type:'POST', data:{name:'oldboyedu'}, headers:{ X-CSRFToken: $.cookie('csrftoken') }, dataType:'json', // arg = JSON.parse('{"k1":123}') success:function(arg){ console.log(arg) } })
<body> <input type="button" onclick="Do1();" value="Do it"/> <input type="button" onclick="Do2();" value="Do it"/> <input type="button" onclick="Do3();" value="Do it"/> <script src="/static/jquery-3.3.1.min.js"></script> <script src="/static/jquery.cookie.js"></script> <script> $.ajaxSetup({ // 為所有Ajax請求添加函數 beforeSend: function(xhr, settings) { xhr.setRequestHeader("X-CSRFToken", $.cookie('csrftoken')); } }); function Do1(){ $.ajax({ url:"/index/", data:{id:1}, type:'POST', success:function(data){ console.log(data); } }); } function Do2(){ $.ajax({ url:"/index/", data:{id:1}, type:'POST', success:function(data){ console.log(data); } }); } function Do3(){ $.ajax({ url:"/index/", data:{id:1}, type:'POST', success:function(data){ console.log(data); } }); } </script> </body>
- Django的Form的作用
1. 幫助我們生成HTML標簽 2. 對用戶輸入的數據進行校驗 ps:form對象是個可迭代對象 Q:從數據庫獲取數據時,下拉框無法實時刷新。 A:重寫構造方法,在構造方法中重新去獲取數據 def __str__(self): return self.title
- 緩存怎么用;
- CSRF是什么,django是如何避免的;XSS呢;
- 如果你來設計login,簡單的說一下思路;
- session和cookie的聯系與區別;session為什么說是安全的;
- WSGI和Nginx的作用;
- 瀏覽器緩存機制
- 你看過django的admin源碼么;看過flask的源碼么;你如何理解開源;
- QAQ
Flask部分( 14 )
- FLask和Django的區別
- 對於Django來說:內部組件全面,自身功能強大,給人一種大而全的感覺,
( 你知 或者不知他,Django就在那里,不悲不喜。 你念 或者不念他,功能就在那里,不來不去。 你愛 或者不愛他,組件就在那里,不增不減。 你用,或者不用他,Django就在你手裡。不捨不棄。)
而Flask:內置組件就很少,但它的第三方組件很多,可擴展性強,還可以自定義組件,
- 兩個框架本身都沒有寫sockte,都是基於wsgi協議做的,而flask框架中的上下文管理較為耀眼。 - 相同點:它們兩個框架都沒有寫sockte,都是基於wsgi協議做的 請求相關數據傳遞的方式不同:django:通過傳遞request參數取值 flask:見問題二 組件不同:django組件多 flask組件少,第三方組件豐富 - 談談你對Flask與Django框架的認識
相同: 都基於wsgi, 不同: 對請求處理不同:Flask基於上下文管理;Django通過傳值來處理 Django功能多,內置組件全面:缺點不能自定義添加或刪除組件 Flask內置組件少,但是可以通過第三方組件來擴展:Flask-email,Flask-SQLAlchemy,Flask-session等
- Flask中的session是什么時候創建,什么時候銷毀的?
當請求進來時,會將 requset 和 session 封裝為一個 RequestContext 對象,通過 LocalStack 將 RequestContext 放入到Local對象中,
因為請求第一次來 session 是空值,所以執行 open_session,給 session(uuid4())賦值,再通過視圖函數處理,請求響應時執行save.session,
將簽名 session 寫入 cookie 中,再將 Local 中的數值pop掉。 - Flask為什么把請求放到RequestContext中?
因為 request 和 session 都是在視圖中操作頻繁的數據,也是用戶請求需要用的數據, 將 request 和 session 封裝在 RequestContext 中 top,pop 一次就可以完成,而單獨不封裝在一起就會多次操作,
- flask中一共有幾個LocalStack和Local對象
兩個LocalStack,兩個Local: - request、session 共同用一個 LocalStack 和 Local - g、app 共同用一個 Localstack 和 Local
- Flask上下文管理是如何實現的:
- 前提:記得不太清楚了,/or 最近剛看過 簡單來說,falsk上下文管理可以分為三個階段: 1、請求進來時,將請求相關的數據放入上下文管理中 2、在視圖函數中,要去上下文管理中取值 3、請求響應,要將上下文管理中的數據清除 詳細點來說: 1、請求剛進來,將request,session封裝在RequestContext類中,app,g封裝在AppContext類中,並通過LocalStack將requestcontext和appcontext放入Local類中 2、視圖函數中,通過localproxy--->偏函數--->localstack--->local取值 3、請求相應時,先執行save.session()再各自執行pop(),將local中的數據清除
- Local的作用?
- 用於保存: - 請求上下文對象 - App上下文對象 - 並且可以做到"線程"間的數據隔離。 線程:threading.local 協程:greenlet.get_current as get_get_ident - localstack 的源碼與 threading.local(線程處理)的作用相似, 不同之處是 Local 是通過 greenlet(協程)獲取唯一標識,粒度更細
- LocalStack的作用?
將local對象中的數據維護成一個棧【ctx,ctx】(先進后出) { “協程或線程的唯一標識”: { stack:[ctx,ctx,ctx,] } }
- 為什么要將Local對象中的數據維護成一個棧
當是web應用時:不管是單線程還是多線程,棧中只有一個數據 - 服務端單線程: { 111:{stack: [ctx, ]} } - 服務端多線程: { 111:{stack: [ctx, ]} 112:{stack: [ctx, ]} } 離線腳本:可以在棧中放入多個數據,在任何情況下都可以獲取到當前app的請求和響應 with app01.app_context(): print(current_app) with app02.app_context(): print(current_app) print(current_app)
- 什么是G?
- G 相當於一次請求的全局變量,當請求進來時將 G 和 current_app 封裝為一個 APPContext 類,在通過 LocalStack 將 Appcontext 放入 Local 中,
取值時通過偏函數,LocalStack、loca 中取值,響應時將 Local 中的 g 數據刪除:
- 應用場景:
befor_request + G = 權限認證系統 - 如何獲取session/g
通過 、偏函數(lookup_req_object)、Localstack、Local 取值
- Flask內置功能:
- 內置組件 - 配置 - 路由 - 視圖 - 模板 - session - 藍圖 - 閃現 - 裝飾器 - 中間件 - 第三方組件 - Flask-session # 將原來保存在cookie中的session數據,放到Redis/memcache/文件/數據庫中 - Flask-migrate # 做數據庫遷移 - Flask-script # - Flask-SQLAlchemy # ORM - blinker - 公共: - DButils # 數據庫連接池: 兩種模式; 為每個參數設置一個連接/共享一個連接;全局參數 - wtforms # form組件:做表單驗證+生成HTML標簽 - gevent-websocket - 自定義組件: - flask-login
- 手寫:自己寫一個類+列表, 實現棧的功能(LocalStack)
分組函數 : group by 字段 having 判斷條件 (固定語法)分組和聚合函數搭配 分組函數 : group by 字段 having 判斷條件 (固定語法)分組和聚合函數搭配 class Stack(): def __init__(self,size): self.size=size self.stack=[] def getstack(self): """ #獲取棧當前數據 :return: """ return self.stack def __str__(self): return str(self.stack) def top(self,x): # 入棧之前檢查棧是否已滿 if self.isfull(): raise Exception("stack is full") else: self.stack.append(x) def pop(self): """ # 出棧之前檢查棧是否已空 :return: """ if self.isempty(): raise Exception("stack is empty") else: self.stack.pop() def isfull(self): """ 判斷棧滿 :return: """ if len(self.stack)==self.size: return True return False def isempty(self): """ 判斷棧空 :return: """ if len(self.stack)==0: return True return False if __name__ == '__main__' : stack=Stack(4) for i in range(11): stack.top(i) print(stack.getstack()) for i in range(3): stack.pop() print(stack.getstack())
- 什么是threading.local,以及他的作用
- 原生SQL和ORM的區別
# 關系對象映射,本質是 - SQL - 執行效率更高,但是代碼更多,開發效率低 - ORM - 開發效率高,編寫速度快,執行效率相比於優化后的SQL較低些
- 反射在哪里用到過
Redis ( )
- 1
- 2
- 3
- 4
- 5
- 6