我python写的闭包为什么效率很低_GitHub - llzhi001/interview_python_practice: interview 面试题 CS-Notes之ME-技术总结...
Star過的Github書籍
值得一看的文章
兩地書
服務發現
服務注冊、服務發現作為構建微服務架構得基礎設施環節,重要性不言而喻。在當下,比較熱門用于做服務注冊和發現的開源項目包括zookeeper、etcd、euerka和consul
consul
1.架構
etcd
kubernetes
架構
Distributed-Task-Queue分布式隊列
celery
dkron
2.基礎架構
Dkron分布式定時任務系統 Github
Dkron是一個分布式,啟動迅速,容錯的定時任務系統,支持cron表達式。
Dkron特點:
易用:易操作和漂亮的UI
可靠:支持容錯
高可擴展性:能夠處理大量的計劃作業和數千個節點
Dkron是用Go編寫的,它利用Raft協議和Serf的強大功能提供容錯性、可靠性和可擴展性,同時保持簡單易安裝。
Dkron-v2整體架構圖
Dkron每個節點都是由一個web服務、grpc服務、raft服務、serf服務、badger數據庫構成。
web負責轉發來自前端job的元信息給grpc服務,一般的grpc操作都在leader節點進行。job的調度和修改保存都要通過leader,只有獲取job的信息不需要到leader節點,因為每個節點的數據是一致的。有人會說這樣的話那是不是leader的壓力會不會太大,不必擔心,由于對于job的增刪改其實請求是很小的,而且job的執行也不是在leader,所以大可不必擔心。
Serf用于服務發現和節點故障提醒,提供節點成員信息,執行job任務。
嵌入式數據庫badger負責在每個節點存儲數據,通過Raft協議保證數據一致性。
Dkron的每個節點在運行的服務上都是相同的,但存在一個仲裁節點leader,job的增刪改都需要直接通過它來進行,但查詢job不需要通過leader在本機即可查詢。job更新后leader的調度器job schedule會重啟一次,調度器只會在leader節點運行。
當集群中當前的leader失去leader地位時,它會關閉job schedule,而獲得leader地位的節點會啟動job schedule,這就保證了任務只會執行一次。
當leader的調度器檢查到將有任務需要執行時,它會發一個serf的消息,serf會隨機發送給任意一個節點去執行,當執行完成后會通知leader的執行結果,并寫進數據庫。
job執行流程圖:
在leader節點處,當job schedule的任務觸發時,leader發送一個serf消息(1-serf msg),serf會隨機選擇一個節點發送。當收到serf發送的執行job的消息后,節點會啟動一個協程去運行job(2-run job),接著返回給serf收到運行消息并正在執行任務的響應(3-serf msg resp)。
當Run job結束后會根據hash一致性隨機選擇一個節點發送grpc消息,將執行結果發送出去(4-Job Done),這里為什么不直接發給leader呢?是因為有可能當時存在leader未選舉出來。因此隨機選擇一個節點,再將請求轉發到leader,保證執行結果一定能發到leader(5-Job Done)。
最后leader會通過raft把數據復制到各個節點,最終一個任務就執行結束了。
分布式消息系統
Kafka
分布式算法
CAP 定理
CAP原則又稱CAP定理,指的是在一個分布式系統中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分區容錯性),三者不可得兼。
對于一個分布式系統,不能同時滿足一下三點:
一致性(C):在分布式系統中的所有數據備份,在同一時刻是否同樣的值。(等同于所有節點訪問同一份最新的數據副本)
可用性(A):在集群中一部分節點故障后,集群整體是否還能響應客戶端的讀寫請求。(對數據更新具備高可用性)
分區容忍性(P):以實際效果而言,分區相當于對通信的時限要求。系統如果不能在時限內達成數據一致性,就意味著發生了分區的情況,必須就當前操作在C和A之間做出選擇。
CAP原則的精髓就是要么AP,要么CP,要么AC,但是不存在CAP。如果在某個分布式系統中數據無副本, 那么系統必然滿足強一致性條件, 因為只有獨一數據,不會出現數據不一致的情況,此時C和P兩要素具備,但是如果系統發生了網絡分區狀況或者宕機,必然導致某些數據不可以訪問,此時可用性條件就不能被滿足,即在此情況下獲得了CP系統,但是CAP不可同時滿足
弱一致性
最終一致性
DNS(Domain Name System)
Gossip(Cassandra的通信協議)
強一致性
同步
Paxos
Raft(multi-paxos)
ZAB(multi-poxos)
RAFT
Git
ELK
Prometheus
數據庫
MySQL
Redis
CNCF
Design Pattern設計模式理論
Design Pattern設計模式實操
Python源碼原理解析
Python Fool趣事
Python基礎
Python語言基本
3.列出 5 個常用 Python 標準庫?
os, logging, system, time, re, math,threading
4.Python的內建數據類型有哪些?
string, int, list, tuple, dict
5.簡述 with 方法打開處理文件幫我我們做了什么?
with 語句適用于對資源進行訪問的場合,確保不管使用過程中是否發生異常都會執行必要的“清理”操作,釋放資源,比如文件使用后自動關閉、線程中鎖的自動獲取和釋放等。
with語句即“上下文管理器”,在程序中用來表示代碼執行過程中所處的前后環境 上下文管理器:含有__enter__和__exit__方法的對象就是上下文管理器。
enter():在執行語句之前,首先執行該方法,通常返回一個實例對象,如果with語句有as目標,則將對象賦值給as目標。
exit():執行語句結束后,自動調用__exit__()方法,用戶釋放資源,若此方法返回布爾值True,程序會忽略異常。
使用環境:文件讀寫、線程鎖的自動釋放等。
6.Python的可變和不可變數據類型?
可變 list, dict, set
不可變 int string tuple
7.Python 獲取當前日期?
from datetime import datetime; datetime.now()
8.談談對 Python 的了解和其他語言的區別
python是典型的動態類型強類型語言
強類型語言, 不需要隱士轉換
解釋性, 解釋型語言使用解釋器將源碼逐行解釋成機器碼并立即執行,不會進行整體性的編譯和鏈接處理,相當于把編譯語言中的編譯和解釋混合到一起同時完成。
簡潔優雅 ,面向對象,跨平臺,
Python是動態類型語言,而Java是靜態類型語言.
9.說說你知道的Python3 和 Python2 之間的區別
print, string/unicode, exception, divide, xrange,
10.了解 Python 之禪么?
import this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
優美勝于丑陋(Python 以編寫優美的代碼為目標)
明了勝于晦澀(優美的代碼應當是明了的,命名規范,風格相似)
簡潔勝于復雜(優美的代碼應當是簡潔的,不要有復雜的內部實現)
復雜勝于凌亂(如果復雜不可避免,那代碼間也不能有難懂的關系,要保持接口簡潔)
扁平勝于嵌套(優美的代碼應當是扁平的,不能有太多的嵌套)
間隔勝于緊湊(優美的代碼有適當的間隔,不要奢望一行代碼解決問題)
可讀性很重要(優美的代碼是可讀的)
即便假借特例的實用性之名,也不可違背這些規則(這些規則至高無上)
不要包容所有錯誤,除非你確定需要這樣做(精準地捕獲異常,不寫 except:pass 風格的代碼)
當存在多種可能,不要嘗試去猜測
而是盡量找一種,最好是唯一一種明顯的解決方案(如果不確定,就用窮舉法)
雖然這并不容易,因為你不是 Python 之父(這里的 Dutch 是指 Guido )
做也許好過不做,但不假思索就動手還不如不做(動手之前要細思量)
如果你無法向人描述你的方案,那肯定不是一個好方案;反之亦然(方案測評標準)
命名空間是一種絕妙的理念,我們應當多加利用(倡導與號召)
11.了解 docstring 么?
文檔字符串是一個重要工具,用于解釋文檔程序 ,幫助你的程序文檔更加簡單易懂。 我們可以在函數體的第一行使用一對三個單引號 或者一對三個雙引號 來定義文檔字符串。 你可以使用 doc 調用函數中的文檔字符串屬性
12.了解類型注解么?
def list_to_str (param_list:list,connect_str: str = " ") - > str:
paas
python3 中注解用來給參數, 返回值,變量的類型加上注解,對代碼沒影響
Python提供了一個工具方便我們測試類型注解的正確性
pip install mypy
mypy demo.py
若無錯誤則無輸出
13.例舉你知道 Python 對象的命名規范,例如方法或者類等
變量命名:字母數字下劃線,不能以數字開頭
_ 受保護的
__ 私有的
init 內置變量
函數和方法(類中叫做方法,模塊中稱作函數)命名 :
14.例舉幾個規范 Python 代碼風格的工具
pylint,yapf, autopep8, flake8
15.一個編碼為 GBK 的字符串 S,要將其轉成 UTF-8 編碼的字符串,應如何操作?
demo_str = "demo".encode("gbk")
demo=demo_str.decode('gbk').encode('utf-8')
16.用正則切分字符串去除非符號
s="info:xiaoZhang 33 shandong"
['info', 'xiaoZhang', '33', 'shandong']
re.compile(r'\W').split(s)
17.單引號、雙引號、三引號的區別?
在不需要轉義的時候, 單引號和雙引號無區別
"abc 'wewe'we"
'abc "wewe"we'
'abc \'wewe\'we'
18.[[1,2],[3,4],[5,6]]一行代碼展開該列表,得出[1,2,3,4,5,6]
question_list = [[1,2],[3,4],[5,6]]
[a for inside in question_list for a in inside]
19.哪些不能作為字典的健
字典中的鍵是不可變類型,可變類型list和dict不能作為字典鍵
一個對象能不能作為字典的key,就取決于其有沒有__hash__方法
20.如何交換字典 {"A":1,"B":2}的鍵和值?
result_dic = {v: k for k, v in demo_dic.items()}
21.對生成器類型的對象實現切片功能
import itertools
itertools.islice(gener, 10, 20)
22.關于list tuple copy 和 deepcopy 的區別是什么?
tuple:
a = (1, 2, 3, [4, 5, 6, 7], 8)
a[3] = 3 //typeerror
a[3][3] = 9 // a (1, 2, 3, [4, 5, 6, 9], 8)
列表是可變數據類型,數據的值可以修改的
這里只是修改了元祖子對象的值,而不是修改了元祖的值
修改可變類型的值不會改變內存id,因此元祖的引用還是沒有發生變化
可以這么理解,只要不修改元祖中值的內存id,那么就可以進行“修改元祖”操作擴展,
面試官可能會問到:元祖是否可以被修改?
答:元祖是不可變數據類型,因此不能修改元祖中的值,但是如果元組中有可變數據類型,那么可以修改可變數據類型中的值,修改可變數據類型的值并不會使其內存id發生變化,所以元祖中元素中的內存id也沒有改變,因此就做到了“修改元祖”操作
list:
a = [1,2,[3,4]]
b = a
c = a[:]
d = a.copy()
e = copy.deepcopy(a)
id(a), id(b), id(c), id(d), id(e) // 只有a b 是同一個指向
>>> (4398429512, 4398429512, 4398398664, 4398429576, 4398429192)
a.append(5) // 只有b跟著改變
a, b, c,d,e
([1, 2, [3, 4], 5], [1, 2, [3, 4], 5], [1, 2, [3, 4]], [1, 2, [3, 4]], [1, 2, [3, 4]])
a[2][1] = 7 // 除了deepcopy, 其他都跟著變了
a, b, c,d,e
([1, 2, [3, 7], 5], [1, 2, [3, 7], 5], [1, 2, [3, 7]], [1, 2, [3, 7]], [1, 2, [3, 4]])
copy 僅拷貝對象本身,而不拷貝對象中引用的其它對象。
deepcopy 除拷貝對象本身,而且拷貝對象中引用的其它對象。(子對象)
23.代碼中經常遇到的*args, **kwargs 含義及用法。
args 是 arguments 的縮寫,表示位置參數
kwargs 是 keyword arguments 的縮寫,表示關鍵字參數
24.Python 中會有函數或成員變量包含單下劃線前綴和結尾,和雙下劃線前綴結尾,區別是什么?
下劃線開頭的命名方式被常用于模塊中,在一個模塊中以單下劃線開頭的變量和方法會被默認劃入模塊內部范圍。
當使用 from my_module import * 導入時,單下劃線開頭的變量和方法是不會被導入的。但使用 import my_module 導入的話,仍然可以用 my_module._var 這樣的形式訪問屬性或方法。
雙下劃線開頭和結尾的是一些 python 的“魔術”對象
class A中定義的屬性__cont ,這樣的變量獲取時需要用A._A__cont
25.json 序列化時,可以處理的數據類型有哪些?如何定制支持 datetime 類型?
json序列化時,可以處理列表、字典、字符、數值、布爾和None
定制datetime類型↓
26.json 序列化時,默認遇到中文會轉換成 unicode,如果想要保留中文怎么辦?
print(json.dumps(dict_demo, ensure_ascii=False))
27.如果當前的日期為 20190530,要求寫一個函數輸出 N 天后的日期,(比如 N 為 2,則輸出 20190601)
from datetime import datetime, timedelta
now_date = "20190530"
now_date = datetime.strptime(now_date, "%Y%m%d").date()
offset = timedelta(days=2)
(now_date + offset).strftime("%Y%m%d")
28.python 字典和 json 字符串相互轉化方法
#導包
import json
#json字符串轉換成字典
json.loads(json_str)
#字典轉換成json字符串
json.dumps(dict)
29.函數裝飾器有什么作用?請列舉說明?
1,引入日志 2,函數執行時間統計3,執行函數前預備處理4,執行函數后清理功能5,權限校驗等場景6,緩存7,事務處理
30.call
可以調用的對象: 一個特殊的魔術方法可以讓類的實例的行為表現的像函數一樣
class Entity:
'''調用實體來改變實體的位置。'''
def __init__(self, size, x, y):
self.x, self.y = x, y
self.size = size
def __call__(self, x, y):
'''改變實體的位置'''
self.x, self.y = x, y
e = Entity(1, 2, 3) // 創建實例
e(4, 5) //實例可以象函數那樣執行,并傳入x y值,修改對象的x y
31.如何判斷一個對象是函數還是方法?
在類外聲明def為函數
類中聲明def:使用類調用為函數,使用實例化對象調用為方法
可以使用isinstance()判斷
class Work(object):
def show(self):
print("執行show方法")
work = Work()
print(Work.show)
print(work.show)
結果:
>
from types import MethodType,FunctionType
print(isinstance(Work.show,FunctionType))
print(isinstance(work.show,MethodType))
結果:
True
True
32.python實現接口 ?
接口只是定義了一些方法,而沒有去實現,多用于程序設計時,只是設計需要有什么樣的功能,但是并沒有實現任何功能,這些功能需要被另一個類(B)繼承后,由 類B去實現其中的某個功能或全部功能。
遵循:開放封閉原則,依賴導致原則,接口隔離原則,繼承多態。
編程思想:為子類做規范; 歸一化設計:幾個類都實現了相同的方法
抽象類:最好單繼承,且可以簡單的實現功能,接口類:可以多繼承,且最好不實現具體功能
在python中接口由抽象類和抽象方法去實現,接口是不能被實例化的,只能被別的類繼承去實現相應的功能。
個人覺得接口在python中并沒有那么重要,因為如果要繼承接口,需要把其中的每個方法全部實現,否則會報編譯錯誤,還不如直接定義一個class,其中的方法實現全部為pass,讓子類重寫這些函數。
方法一:用抽象類和抽象函數實現方法(適用于單繼承)
方法二:用普通類定義接口(推薦)
33.Python 中的反射了解么?
在Python中,能夠通過一個對象,找出其type、class、attribute或method的能力,稱為反射或自省
具有反射能力的函數有type(),isinstance(),callable().dir().getattr()等
34.metaclass or type
35.Python中遞歸的最大次數1000 ?怎么改
import sys
sys.setrecursionlimit(1500) # set the maximum depth as 1500
36.列舉 5 個 Python 中的異常類型以及其含義
BaseException
+-- SystemExit
+-- KeyboardInterrupt
+-- GeneratorExit
+-- Exception
+-- StopIteration
+-- StopAsyncIteration
+-- ArithmeticError
| +-- FloatingPointError
| +-- OverflowError
| +-- ZeroDivisionError
+-- AssertionError
+-- AttributeError
+-- BufferError
+-- EOFError
+-- ImportError
| +-- ModuleNotFoundError
+-- LookupError
| +-- IndexError
| +-- KeyError
+-- MemoryError
+-- NameError
| +-- UnboundLocalError
+-- OSError
| +-- BlockingIOError
| +-- ChildProcessError
| +-- ConnectionError
| | +-- BrokenPipeError
| | +-- ConnectionAbortedError
| | +-- ConnectionRefusedError
| | +-- ConnectionResetError
| +-- FileExistsError
| +-- FileNotFoundError
| +-- InterruptedError
| +-- IsADirectoryError
| +-- NotADirectoryError
| +-- PermissionError
| +-- ProcessLookupError
| +-- TimeoutError
+-- ReferenceError
+-- RuntimeError
| +-- NotImplementedError
| +-- RecursionError
+-- SyntaxError
| +-- IndentationError
| +-- TabError
+-- SystemError
+-- TypeError
+-- ValueError
| +-- UnicodeError
| +-- UnicodeDecodeError
| +-- UnicodeEncodeError
| +-- UnicodeTranslateError
+-- Warning
+-- DeprecationWarning
+-- PendingDeprecationWarning
+-- RuntimeWarning
+-- SyntaxWarning
+-- UserWarning
+-- FutureWarning
+-- ImportWarning
+-- UnicodeWarning
+-- BytesWarning
+-- ResourceWarning
37.w、a+、wb 文件寫入模式的區別
r : 讀取文件,若文件不存在則會報錯
w: 寫入文件,若文件不存在則會先創建再寫入,會覆蓋原文件
a : 寫入文件,若文件不存在則會先創建再寫入,但不會覆蓋原文件,而是追加在文件末尾
rb,wb:分別于r,w類似,用于讀寫二進制文件
r+ : 可讀、可寫,文件不存在也會報錯,寫操作時會覆蓋
w+ : 可讀,可寫,文件不存在先創建,會覆蓋
a+ :可讀、可寫,文件不存在先創建,不會覆蓋,追加在末尾
38.舉例 sort 和 sorted 的區別
使用sort()方法對list排序會修改list本身,不會返回新list,sort()不能對dict字典進行排序;
sorted方法對可迭代的序列排序生成新的序列,對dict排序默認會按照dict的key值進行排序,最后返回的結果是一個對key值排序好的list;
sorted對tuple, dict依然有效,而sort不行
39.在 requests 模塊中,requests.content 和 requests.text 什么區別
.content中間存的是字節碼 .text存的是.content編碼后的字符串
操作方式就是,如果想取得文本就用.text,如果想獲取圖片,就用.content
40.python新式類和經典類的區別
這2篇文章很好的介紹了新式類的特性:
新式類多繼承搜索順序(廣度優先):先在水平方向查找,然后再向上查找
經典類多繼承搜索順序(深度優先):先深入繼承樹左側查找,然后再返回,開始查找右側
41.字符串的操作題目
全字母短句 PANGRAM 是包含所有英文字母的句子,比如:A QUICK BROWN FOX JUMPS OVER THE LAZY DOG. 定義并實現一個方法 get_missing_letter, 傳入一個字符串采納數,返回參數字符串變成一個 PANGRAM 中所缺失的字符。應該忽略傳入字符串參數中的大小寫,返回應該都是小寫字符并按字母順序排序(請忽略所有非 ACSII 字符)
下面示例是用來解釋,雙引號不需要考慮:
(0)輸入: "A quick brown for jumps over the lazy dog"
返回: ""
(1)輸入: "A slow yellow fox crawls under the proactive dog"
返回: "bjkmqz"
(2)輸入: "Lions, and tigers, and bears, oh my!"
返回: "cfjkpquvwxz"
(3)輸入: ""
返回:"abcdefghijklmnopqrstuvwxyz"
def get_missing_letter(a):
s1 = set("abcdefghijklmnopqrstuvwxyz")
s2 = set(a)
ret = "".join(sorted(s1-s2))
return ret
print(get_missing_letter("python"))
42.可變類型和不可變類型
1,可變類型有list,dict.不可變類型有string,number,tuple.
2,當進行修改操作時,可變類型傳遞的是內存中的地址,也就是說,直接修改內存中的值,并沒有開辟新的內存。
3,不可變類型被改變時,并沒有改變原內存地址中的值,而是開辟一塊新的內存,將原地址中的值復制過去,對這塊新開辟的內存中的值進行操作。
43.is和==有什么區別?
a = 1024
b = 1024
a is b >False
a == b > True
is:比較的是兩個對象的id值是否相等,也就是比較倆對象是否為同一個實例對象。是否指向同一個內存地址
== : 比較的兩個對象的內容/值是否相等,默認會調用對象的eq()方法
44.求出列表所有奇數并構造新列表
a = [1,2,3,4,5,6,7,8,9,10]
res = [ i for i in a if i%2==1]
print(res)
45.用一行python代碼寫出1+2+3+10248
from functools import reduce
#1.使用sum內置求和函數
num = sum([1,2,3,10248])
print(num)
#2.reduce 函數
num1 = reduce(lambda x,y :x+y,[1,2,3,10248])
print(num1)
46.Python中變量的作用域?(變量查找順序)
函數作用域的LEGB順序
1.什么是LEGB?
L: local 函數內部作用域
E: enclosing 函數內部與內嵌函數之間
G: global 全局作用域
B: build-in 內置作用
python在函數里面的查找分為4種,稱之為LEGB,也正是按照這是順序來查找的
47.字符串 "123" 轉換成 123,不使用內置api,例如 int()
方法一: 利用 str 函數
def atoi(s):
num = 0
for v in s:
for j in range(10):
if v == str(j):
num = num * 10 + j
return num
方法二: 利用 ord 函數
def atoi(s):
num = 0
for v in s:
num = num * 10 + ord(v) - ord('0')
return num
方法三: 利用 eval 函數
def atoi(s):
num = 0
for v in s:
t = "%s * 1" % v
n = eval(t)
num = num * 10 + n
return num
方法四: 結合方法二,使用 reduce,一行解決
from functools import reduce
def atoi(s):
return reduce(lambda num, v: num * 10 + ord(v) - ord('0'), s, 0)
48.Given an array of integers
給定一個整數數組和一個目標值,找出數組中和為目標值的兩個數。你可以假設每個輸入只對應一種答案,且同樣的元素不能被重復利用。示例:給定nums = [2,7,11,15],target=9 因為 nums[0]+nums[1] = 2+7 =9,所以返回[0,1]
def two_sum(nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
for i in nums:
if target - i in nums and i is not target-i:
return [nums.index(i), nums.index(target - i)]
nums_all = [2, 7, 11, 15]
target = 9
nums = two_sum(nums_all, target)
print(nums)
49.有一個jsonline格式的文件file.txt大小約為10K
def get_lines():
with open('file.txt','rb') as f:
return f.readlines()
if __name__ == '__main__':
for e in get_lines():
process(e) # 處理每一行數據
現在要處理一個大小為10G的文件,但是內存只有4G,如果在只修改get_lines 函數而其他代碼保持不變的情況下,應該如何實現?需要考慮的問題都有那些?
def get_lines():
with open('file.txt','rb') as f:
for i in f:
yield i
Pandaaaa906提供的方法
from mmap import mmap
def get_lines(fp):
with open(fp,"r+") as f:
m = mmap(f.fileno(), 0)
tmp = 0
for i, char in enumerate(m):
if char==b"\n":
yield m[tmp:i+1].decode()
tmp = i+1
if __name__=="__main__":
for i in get_lines("fp_some_huge_file"):
print(i)
50.返回該文件夾中所有文件的路徑
def print_directory_contents(sPath):
"""
這個函數接收文件夾的名稱作為輸入參數
返回該文件夾中文件的路徑
以及其包含文件夾中文件的路徑
"""
import os
for s_child in os.listdir(s_path):
s_child_path = os.path.join(s_path, s_child)
if os.path.isdir(s_child_path):
print_directory_contents(s_child_path)
else:
print(s_child_path)
51.設計實現遍歷目錄與子目錄,抓取.pyc文件
第一種方法:
import os
def get_files(dir,suffix):
res = []
for root,dirs,files in os.walk(dir):
for filename in files:
name,suf = os.path.splitext(filename)
if suf == suffix:
res.append(os.path.join(root,filename))
print(res)
get_files("./",'.pyc')
第二種方法:
import os
def pick(obj):
if ob.endswith(".pyc"):
print(obj)
def scan_path(ph):
file_list = os.listdir(ph)
for obj in file_list:
if os.path.isfile(obj):
pick(obj)
elif os.path.isdir(obj):
scan_path(obj)
if __name__=='__main__':
path = input('輸入目錄')
scan_path(path)
第三種方法
from glob import iglob
def func(fp, postfix):
for i in iglob(f"{fp}/**/*{postfix}", recursive=True):
print(i)
if __name__ == "__main__":
postfix = ".pyc"
func("K:\Python_script", postfix)
52.輸入日期, 判斷這一天是這一年的第幾天?
import datetime
def dayofyear():
year = input("請輸入年份: ")
month = input("請輸入月份: ")
day = input("請輸入天: ")
date1 = datetime.date(year=int(year),month=int(month),day=int(day))
date2 = datetime.date(year=int(year),month=1,day=1)
return (date1-date2).days+1
53.打亂一個排好序的list對象alist?
import random
alist = [1,2,3,4,5]
random.shuffle(alist)
print(alist)
# 下面這段代碼是shuffle的實現
items = list(alist)
for i in xrange(len(alist)):
alist[i] = items.pop(self.randrange(len(items)))
54.現有字典 d= {'a':24,'g':52,'i':12,'k':33}請按value值進行排序?
sorted(d.items(),key=lambda x:x[1])
55.字典推導式
# 將字符串 "k:1 |k1:2|k2:3|k3:4",處理成字典 {k:1,k1:2,...}
# d = {key:value for (key,value) in iterable}
d = {k:int(v) for t in str1.split("|") for k, v in (t.split(":"), )}
56.請反轉字符串 "aStr"?
print("aStr"[::-1])
57.請按alist中元素的age由大到小排序
alist = [{'name':'a','age':20},{'name':'b','age':30},{'name':'c','age':25}]
def sort_by_age(list1):
return sorted(alist, key=lambda x:x['age'], reverse=True)
58.下面代碼的輸出結果將是什么?
list = ['a','b','c','d','e']
print(list[10:])
代碼將輸出[],不會產生IndexError錯誤,就像所期望的那樣,嘗試用超出成員的個數的index來獲取某個列表的成員。例如,嘗試獲取list[10]和之后的成員,會導致IndexError。然而,嘗試獲取列表的切片,開始的index超過了成員個數不會產生IndexError,而是僅僅返回一個空列表。這成為特別讓人惡心的疑難雜癥,因為運行的時候沒有錯誤產生,導致Bug很難被追蹤到。
59.寫一個列表生成式,產生一個公差為11的等差數列
print([x*11 for x in range(10)])
60.給定兩個列表,怎么找出他們相同的元素和不同的元素?
list1 = [1,2,3]
list2 = [3,4,5]
set1 = set(list1)
set2 = set(list2)
print(set1 & set2)
print(set1 ^ set2)
61.統計一個文本中單詞頻次最高的10個單詞?
import re
def test(filepath):
distone = {}
numTen = []
with open(filepath,"r",encoding="utf-8") as f:
for line in f:
line = re.sub("\W","",line)
lineone = line.split()
for keyone in lineone:
if not distone.get(keyone):
distone[keyone]=1
else:
distone[keyone]+=1
numTen = sorted(distone.items(),key=lambda x:x[1],reverse=True)[:10]
numTen =[x[0]for x in numTen]
return numTen
62.給定一個任意長度數組,實現一個函數
讓所有奇數都在偶數前面,而且奇數升序排列,偶數降序排序,如字符串'1982376455',變成'1355798642'
def func1(l):
if isinstance(l,str):
l = list(l)
l = [int(i) for i in l]
l.sort(reverse=True)
for i in range(len(l)):
if l[i] % 2>0:
l.insert(0,l.pop(i))
print(''.join(str(e) for e in l))
63.寫一個函數找出一個整數數組中,第二大的數
def find_Second_large_num(num_list):
"""
找出數組第2大的數字
"""
#直接排序,輸出倒數第二個數即可
tmp_list = sorted(num_list)
print ("Second_large_num is :",tmp_list[-2])
#設置兩個標志位一個存儲最大數一個存儲次大數
#two 存儲次大值,one存儲最大值,遍歷一次數組即可,先判斷是否大于one,若大于將one的值給two,將num_list[i]的值給one,否則比較是否大于two,若大于直接將num_list[i]的值給two,否則pass
one = num_list[0]
two = num_list[0]
for i in range(1,len(num_list)):
if num_list[i] > one:
two = one
one = num_list[i]
elif num_list[i] > two:
two = num_list[i]
else:
pass
print("Second_large_num is :",two)
if __name__ == '__main___':
num_list = [34,11,23,56,78,0,9,12,3,7,5]
find_Second_large_num(num_list)
64.閱讀一下代碼他們的輸出結果是什么?
def multi():
return [lambda x : i*x for i in range(4)]
print([m(3) for m in multi()])
提示: 閉包,作用域
正確答案是[9,9,9,9],而不是[0,3,6,9]產生的原因是Python的閉包的后期綁定導致的,這意味著在閉包中的變量是在內部函數被調用的時候被查找的,因為,最后函數被調用的時候,for循環已經完成, i 的值最后是3,因此每一個返回值的i都是3,所以最后的結果是[9,9,9,9]
這篇講訴的很詳細了 https://www.cnblogs.com/shiqi17/p/9608195.html
65.統計一段字符串中字符出現的次數
def count_str(str_data):
"""定義一個字符出現次數的函數"""
dict_str = {}
for i in str_data:
dict_str[i] = dict_str.get(i,0)+1
return dict_str
dict_str = count_str("AAABBCCAC")
str_count_data = ""
for k,v in dict_str.items():
str_count_data += k +str(v)
print(str_count_data)
66.super函數的具體用法和場景
Python高級
元類
67.Python中類方法、類實例方法、靜態方法有何區別?
類方法: 是類對象的方法,在定義時需要在上方使用 @classmethod 進行裝飾,形參為cls,表示類對象,類對象和實例對象都可調用
類實例方法: 是類實例化對象的方法,只有實例對象可以調用,形參為self,指代對象本身;
靜態方法: 是一個任意函數,在其上方使用 @staticmethod 進行裝飾,可以用對象直接調用,靜態方法實際上跟該類沒有太大關系
68.遍歷一個object的所有屬性,并print每一個屬性名?
class Car:
def __init__(self,name,loss): # loss [價格,油耗,公里數]
self.name = name
self.loss = loss
def getName(self):
return self.name
def getPrice(self):
# 獲取汽車價格
return self.loss[0]
def getLoss(self):
# 獲取汽車損耗值
return self.loss[1] * self.loss[2]
Bmw = Car("寶馬",[60,9,500]) # 實例化一個寶馬車對象
print(getattr(Bmw,"name")) # 使用getattr()傳入對象名字,屬性值。
print(dir(Bmw)) # 獲Bmw所有的屬性和方法
69.寫一個類,并讓它盡可能多的支持操作符?
class Array:
__list = []
def __init__(self):
print "constructor"
def __del__(self):
print "destruct"
def __str__(self):
return "this self-defined array class"
def __getitem__(self,key):
return self.__list[key]
def __len__(self):
return len(self.__list)
def Add(self,value):
self.__list.append(value)
def Remove(self,index):
del self.__list[index]
def DisplayItems(self):
print "show all items---"
for item in self.__list:
print item
70.介紹Cython,Pypy Cpython Numba各有什么缺點
CPython
CPython is Guido van Rossum’s reference version of the Python computing language. It’s most often called simply “Python”; speakers say “CPython” generally to distinguish it explicitly from other implementations.
CPython是使用最廣的Python解釋器。教程的所有代碼也都在CPython下執行
IPython
IPython是基于CPython之上的一個交互式解釋器,也就是說,IPython只是在交互方式上有所增強
Pypy
PyPy是另一個Python解釋器,它的目標是執行速度。PyPy采用JIT技術,對Python代碼進行動態編譯(注意不是解釋),所以可以顯著提高Python代碼的執行速度。
絕大部分Python代碼都可以在PyPy下運行,但是PyPy和CPython有一些是不同的,這就導致相同的Python代碼在兩種解釋器下執行可能會有不同的結果。如果你的代碼要放到PyPy下執行,就需要了解PyPy和CPython的不同點
Jython
Jython是將Python code在JVM上面跑和調用java code的解釋器。
71.請描述抽象類和接口類的區別和聯系
72.Python中如何動態獲取和設置對象的屬性?
hasattr(), getattr(), setattr()
內存管理與垃圾回收機制
73.哪些操作會導致Python內存泄露,怎么處理?
在使用KafkaProducer 進行消息讀寫的時候, 錯誤的配置了buffer_memory參數的值, 導致每次進行
類調用, 都導致客戶端不斷的重復寫內存,并且因為最開始沒有使用單例模式,導致內存不斷上升,最后溢出。
解決辦法就是修正錯誤的配置了buffer_memory參數的值 和使用單例
buffer_memory (int): The total bytes of memory the producer should use
to buffer records waiting to be sent to the server. If records are
sent faster than they can be delivered to the server the producer
will block up to max_block_ms, raising an exception on timeout.
In the current implementation, this setting is an approximation.
Default: 33554432 (32MB)
74.關于內存溢出和內存泄漏的區別
內存溢出:(Out Of Memory---OOM)
系統已經不能再分配出你所需要的空間,比如你需要100M的空間,系統只剩90M了,這就叫內存溢出
內存泄漏: (Memory Leak)
強引用所指向的對象不會被回收,可能導致內存泄漏,虛擬機寧愿拋出OOM也不會去回收他指向的對象
75.Python的內存管理機制及調優手段?
gc.disable() # 暫停自動垃圾回收.
gc.collect() # 執行一次完整的垃圾回收, 返回垃圾回收所找到無法到達的對象的數量.
gc.set_threshold() # 設置Python垃圾回收的閾值.
gc.set_debug() # 設置垃圾回收的調試標記. 調試信息會被寫入std.err.
Python有兩種共存的內存管理機制: 引用計數和垃圾回收
垃圾回收機制:
引用計數
PyObject
python里每一個東西都是對象,它們的核心就是一個結構體:PyObject
PyObject是每個對象必有的內容,其中ob_refcnt就是做為引用計數。當一個對象有新的引用時,它的ob_refcnt就會增加,當引用它的對象被刪除,它的ob_refcnt就會減少
引用計數也是一種垃圾收集機制,而且也是一種最直觀,最簡單的垃圾收集技術。當 Python 的某個對象的引用計數降為 0 時,說明沒有任何引用指向該對象,該對象就成為要被回收的垃圾了。比如某個新建對象,它被分配給某個引用,對象的引用計數變為 1。如果引用被刪除,對象的引用計數為 0,那么該對象就可以被垃圾回收。不過如果出現循環引用的話,引用計數機制就不再起有效的作用了
標記清除
標記-清除機制,顧名思義,首先標記對象(垃圾檢測),然后清除垃圾(垃圾回收)。
首先初始所有對象標記為白色,并確定根節點對象(這些對象是不會被刪除),標記它們為黑色(表示對象有效)。
將有效對象引用的對象標記為灰色(表示對象可達,但它們所引用的對象還沒檢查),檢查完灰色對象引用的對象后,將灰色標記為黑色。
重復直到不存在灰色節點為止。最后白色結點都是需要清除的對象。
分代回收
從前面“標記-清除”這樣的垃圾收集機制來看,這種垃圾收集機制所帶來的額外操作實際上與系統中總的內存塊的數量是相關的,當需要回收的內存塊越多時,垃圾檢測帶來的額外操作就越多,而垃圾回收帶來的額外操作就越少;反之,當需回收的內存塊越少時,垃圾檢測就將比垃圾回收帶來更少的額外操作
1、新創建的對象做為0代
2、每執行一個【標記-刪除】,存活的對象代數就+1
3、代數越高的對象(存活越持久的對象),進行【標記-刪除】的時間間隔就越長。這個間隔,江湖人稱閥值。
三種情況觸發垃圾回收
1、調用gc.collect()
2、GC達到閥值時
3、程序退出時
調優手段:
1.手動垃圾回收
2.調高垃圾回收閾值
3.避免循環引用
函數
76.什么是Hash(散列函數)?
77.編寫函數的4個原則
1、函數設計要盡量短小,嵌套層次不宜過深。避免過長函數,嵌套最好能控制在3層之內
2、函數申明應該合理,簡單,易于使用。除函數名能夠夠正確反映其大體功能外,參數的設計也應該簡潔明了,參數個數不宜太多
3、函數參數設計應該考慮向下兼容。可以通過加入默認參數來避免退化
4、一個函數只做一件事,就要盡量保證抽象層級的一致性,所有語句盡量在一個粒度上。若在一個函數中處理多件事,不利于代碼的重用
78.函數調用參數的傳遞方式是值傳遞還是引用傳遞?
python不允許程序員選擇采用傳值還是傳引用。Python參數傳遞采用的肯定是“傳對象引用”的方式。這種方式相當于傳值和傳引用的一種綜合。如果函數收到的是一個可變對象(比如字典或者列表)的引用,就能修改對象的原始值--相當于通過“傳引用”來傳遞對象。如果函數收到的是一個不可變對象(比如數字、字符或者元組)的引用,就不能直接修改原始對象--相當于通過“傳值'來傳遞對象。
79.如何在function里面設置一個全局變量
global x
80.帶參數的裝飾器?
def decorator(*dargs, **dkwargs):
def params_wrapper(func):
@wraps(func)
def wrapper(*args, **kwargs):
func(*args, **kwargs)
return wrapper
return params_wrapper
類裝飾器
class decorator(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print('before............')
res = self.func(*args, **kwargs)
print('after............')
return res
81.遞歸函數停止的條件?
遞歸的終止條件一般定義在遞歸函數內部,在遞歸調用前要做一個條件判斷,根據判斷的結果選擇是繼續調用自身,還是return;返回終止遞歸。
終止的條件:
1、判斷遞歸的次數是否達到某一限定值
2、判斷運算的結果是否達到某個范圍等,根據設計的目的來選擇
設計模式
82.對設計模式的理解,簡述你了解的設計模式?
設計模式是經過總結,優化的,對我們經常會碰到的一些編程問題的可重用解決方案。一個設計模式并不像一個類或一個庫那樣能夠直接作用于我們的代碼,反之,設計模式更為高級,它是一種必須在特定情形下實現的一種方法模板。
常見的是工廠模式和單例模式
83.python如何實現單例模式
第一種方法:使用裝飾器
def singleton(cls):
instances = {}
def wrapper(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return wrapper
@singleton
class Foo(object):
pass
foo1 = Foo()
foo2 = Foo()
print foo1 is foo2 #True
第二種方法:使用基類
New 是真正創建實例對象的方法,所以重寫基類的new 方法,以此保證創建對象的時候只生成一個實例
class Singleton(object):
def __new__(cls,*args,**kwargs):
if not hasattr(cls,'_instance'):
cls._instance = super(Singleton,cls).__new__(cls,*args,**kwargs)
return cls._instance
class Foo(Singleton):
pass
foo1 = Foo()
foo2 = Foo()
print foo1 is foo2 #True
84.單例模式的應用場景有那些?
單例模式應用的場景一般發現在以下條件下:
資源共享的情況下,避免由于資源操作時導致的性能或損耗等,如日志文件,應用配置。
控制資源的情況下,方便資源之間的互相通信。如線程池等,
1.網站的計數器
2.應用配置
3.多線程池
4.數據庫配置 數據庫連接池
5.應用程序的日志應用...
85.對裝飾器的理解,并寫出一個計時器記錄方法執行性能的裝飾器?
裝飾器本質上是一個callable object ,它可以讓其他函數在不需要做任何代碼變動的前提下增加額外功能,裝飾器的返回值也是一個函數對象。
import time
from functools import wraps
def timeit(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.clock()
ret = func(*args, **kwargs)
end = time.clock()
print('used:',end-start)
return ret
return wrapper
@timeit
def foo():
print('in foo()'foo())
86.解釋以下什么是閉包?
在函數內部再定義一個函數,并且這個函數用到了外邊函數的變量,那么將這個函數以及用到的一些變量稱之為閉包。
import functools
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs)
print "start"
return func(*args, **kwargs)
return wrapper
87.函數裝飾器有什么作用?
裝飾器本質上是一個callable object,它可以在讓其他函數在不需要做任何代碼的變動的前提下增加額外的功能。裝飾器的返回值也是一個函數的對象,它經常用于有切面需求的場景。比如:插入日志,性能測試,事務處理,緩存。權限的校驗等場景,有了裝飾器就可以抽離出大量的與函數功能本身無關的雷同代碼并發并繼續使用。
詳細參考:https://manjusaka.itscoder.com/2018/02/23/something-about-decorator/
88.生成器,迭代器的區別?
迭代器是遵循迭代協議的對象。用戶可以使用 iter() 以從任何序列得到迭代器(如 list, tuple, dictionary, set 等)。另一個方法則是創建一個另一種形式的迭代器 —— generator 。要獲取下一個元素,則使用成員函數 next()(Python 2)或函數 next() function (Python 3) 。當沒有元素時,則引發 StopIteration 此例外。若要實現自己的迭代器,則只要實現 next()(Python 2)或 __next__()( Python 3)
生成器(Generator),只是在需要返回數據的時候使用yield語句。每次next()被調用時,生成器會返回它脫離的位置(它記憶語句最后一次執行的位置和所有的數據值)
區別: 生成器能做到迭代器能做的所有事,而且因為自動創建iter()和next()方法,生成器顯得特別簡潔,而且生成器也是高效的,使用生成器表達式取代列表解析可以同時節省內存。除了創建和保存程序狀態的自動方法,當發生器終結時,還會自動拋出StopIteration異常。
89.X是什么類型?
X= (i for i in range(10))
X是 generator類型
90.請用一行代碼 實現將1-N 的整數列表以3為單位分組
N =100
print ([[x for x in range(1,100)] [i:i+3] for i in range(0,100,3)])
91.Python中yield的用法?
yield就是保存當前程序執行狀態。你用for循環的時候,每次取一個元素的時候就會計算一次。用yield的函數叫generator,和iterator一樣,它的好處是不用一次計算所有元素,而是用一次算一次,可以節省很多空間,generator每次計算需要上一次計算結果,所以用yield,否則一return,上次計算結果就沒了
面向對象
92.Python的魔法方法
93.談談你對面向對象的理解?
在我理解,面向對象是向現實世界模型的自然延伸,這是一種“萬物皆對象”的編程思想。在現實生活中的任何物體都可以歸為一類事物,而每一個個體都是一類事物的實例。面向對象的編程是以對象為中心,以消息為驅動,所以程序=對象+消息。
面向對象有三大特性,封裝、繼承和多態。
封裝就是將一類事物的屬性和行為抽象成一個類,使其屬性私有化,行為公開化,提高了數據的隱秘性的同時,使代碼模塊化。這樣做使得代碼的復用性更高。
繼承則是進一步將一類事物共有的屬性和行為抽象成一個父類,而每一個子類是一個特殊的父類--有父類的行為和屬性,也有自己特有的行為和屬性。這樣做擴展了已存在的代碼塊,進一步提高了代碼的復用性。
如果說封裝和繼承是為了使代碼重用,那么多態則是為了實現接口重用。多態的一大作用就是為了解耦--為了解除父子類繼承的耦合度。如果說繼承中父子類的關系式IS-A的關系,那么接口和實現類之之間的關系式HAS-A。簡單來說,多態就是允許父類引用(或接口)指向子類(或實現類)對象。很多的設計模式都是基于面向對象的多態性設計的。
總結一下,如果說封裝和繼承是面向對象的基礎,那么多態則是面向對象最精髓的理論。掌握多態必先了解接口,只有充分理解接口才能更好的應用多態
正則表達式
94.請寫出一段代碼用正則匹配出ip?
95.a = “abbbccc”,用正則匹配為abccc,不管有多少b,就出現一次?
re.sub(r'b+', 'b', 'abbbccccc')
96.Python字符串查找和替換?
函數說明
re.match(pat, s)只從字符串s的頭開始匹配,比如(‘123’, ‘12345’)匹配上了,而(‘123’,’01234’)就是沒有匹配上,沒有匹配上返回None,匹配上返回matchobject
re.search(pat, s)從字符串s的任意位置都進行匹配,比如(‘123’,’01234’)就是匹配上了,只要s只能存在符合pat的連續字符串就算匹配上了,沒有匹配上返回None,匹配上返回matchobject
re.sub(pat,newpat,s)對字符串中s的包含的所有符合pat的連續字符串進行替換,如果newpat為str,那么就是替換為newpat,如果newpat是函數,那么就按照函數返回值替換。sub函數兩個有默認值的參數分別是count表示最多只處理前幾個匹配的字符串,默認為0表示全部處理;最后一個是flags,默認為0
97.用Python匹配HTML g tag的時候,<.> 和 <.*?> 有什么區別
98.正則表達式貪婪與非貪婪模式的區別?
如:String str="abcaxc"; Patter p="ab*c";
貪婪匹配:正則表達式一般趨向于最大長度匹配,也就是所謂的貪婪匹配。如上面使用模式p匹配字符串str,結果就是匹配到:abcaxc(abc)。正則引擎默認是貪婪的,當出現""時,它會盡量去匹配盡可能長的字符串
非貪婪匹配:就是匹配到結果就好,就少的匹配字符。如上面使用模式p匹配字符串str,結果就是匹配到:abc(ab*c)。
系統編程
99.進程總結
進程:程序運行在操作系統上的一個實例,就稱之為進程。進程需要相應的系統資源:內存、時間片、pid。
創建進程:
首先要導入multiprocessing中的Process:
創建一個Process對象;
創建Process對象時,可以傳遞參數;
p = Process(target=XXX,args=(tuple,),kwargs={key:value})
target = XXX 指定的任務函數,不用加(),
args=(tuple,)kwargs={key:value}給任務函數傳遞的參數
使用start()啟動進程
結束進程
給子進程指定函數傳遞參數Demo
import os
from mulitprocessing import Process
import time
def pro_func(name,age,**kwargs):
for i in range(5):
print("子進程正在運行中,name=%s,age=%d,pid=%d"%(name,age,os.getpid()))
print(kwargs)
time.sleep(0.2)
if __name__ =="__main__":
#創建Process對象
p = Process(target=pro_func,args=('小明',18),kwargs={'m':20})
#啟動進程
p.start()
time.sleep(1)
#1秒鐘之后,立刻結束子進程
p.terminate()
p.join()
注意:進程間不共享全局變量
進程之間的通信-Queue
在初始化Queue()對象時(例如q=Queue(),若在括號中沒有指定最大可接受的消息數量,獲數量為負值時,那么就代表可接受的消息數量沒有上限一直到內存盡頭)
Queue.qsize():返回當前隊列包含的消息數量
Queue.empty():如果隊列為空,返回True,反之False
Queue.full():如果隊列滿了,返回True,反之False
Queue.get([block[,timeout]]):獲取隊列中的一條消息,然后將其從隊列中移除,
block默認值為True。
如果block使用默認值,且沒有設置timeout(單位秒),消息隊列如果為空,此時程序將被阻塞(停在讀中狀態),直到消息隊列讀到消息為止,如果設置了timeout,則會等待timeout秒,若還沒讀取到任何消息,則拋出“Queue.Empty"異常:
Queue.get_nowait()相當于Queue.get(False)
Queue.put(item,[block[,timeout]]):將item消息寫入隊列,block默認值為True;
如果block使用默認值,且沒有設置timeout(單位秒),消息隊列如果已經沒有空間可寫入,此時程序將被阻塞(停在寫入狀態),直到從消息隊列騰出空間為止,如果設置了timeout,則會等待timeout秒,若還沒空間,則拋出”Queue.Full"異常
如果block值為False,消息隊列如果沒有空間可寫入,則會立刻拋出"Queue.Full"異常;
Queue.put_nowait(item):相當Queue.put(item,False)
進程間通信Demo:
from multiprocessing import Process,Queue
import os,time,random
#寫數據進程執行的代碼:
def write(q):
for value in ['A','B','C']:
print("Put %s to queue...",%value)
q.put(value)
time.sleep(random.random())
#讀數據進程執行的代碼
def read(q):
while True:
if not q.empty():
value = q.get(True)
print("Get %s from queue.",%value)
time.sleep(random.random())
else:
break
if __name__=='__main__':
#父進程創建Queue,并傳給各個子進程
q = Queue()
pw = Process(target=write,args=(q,))
pr = Process(target=read,args=(q,))
#啟動子進程pw ,寫入:
pw.start()
#等待pw結束
pw.join()
#啟動子進程pr,讀取:
pr.start()
pr.join()
#pr 進程里是死循環,無法等待其結束,只能強行終止:
print('')
print('所有數據都寫入并且讀完')
進程池Pool
#coding:utf-8
from multiprocessing import Pool
import os,time,random
def worker(msg):
t_start = time.time()
print("%s 開始執行,進程號為%d"%(msg,os.getpid()))
# random.random()隨機生成0-1之間的浮點數
time.sleep(random.random()*2)
t_stop = time.time()
print(msg,"執行完畢,耗時%0.2f”%(t_stop-t_start))
po = Pool(3)#定義一個進程池,最大進程數3
for i in range(0,10):
po.apply_async(worker,(i,))
print("---start----")
po.close()
po.join()
print("----end----")
進程池中使用Queue
如果要使用Pool創建進程,就需要使用multiprocessing.Manager()中的Queue(),而不是multiprocessing.Queue(),否則會得到如下的錯誤信息:
RuntimeError: Queue objects should only be shared between processs through inheritance
from multiprocessing import Manager,Pool
import os,time,random
def reader(q):
print("reader 啟動(%s),父進程為(%s)"%(os.getpid(),os.getpid()))
for i in range(q.qsize()):
print("reader 從Queue獲取到消息:%s"%q.get(True))
def writer(q):
print("writer 啟動(%s),父進程為(%s)"%(os.getpid(),os.getpid()))
for i ini "itcast":
q.put(i)
if __name__ == "__main__":
print("(%s)start"%os.getpid())
q = Manager().Queue()#使用Manager中的Queue
po = Pool()
po.apply_async(wrtier,(q,))
time.sleep(1)
po.apply_async(reader,(q,))
po.close()
po.join()
print("(%s)End"%os.getpid())
100.談談你對多進程,多線程,以及協程的理解,項目是否用?
這個問題被問的概念相當之大,
進程:一個運行的程序(代碼)就是一個進程,沒有運行的代碼叫程序,進程是系統資源分配的最小單位,進程擁有自己獨立的內存空間,所有進程間數據不共享,開銷大。
線程: cpu調度執行的最小單位,也叫執行路徑,不能獨立存在,依賴進程存在,一個進程至少有一個線程,叫主線程,而多個線程共享內存(數據共享,共享全局變量),從而極大地提高了程序的運行效率。
協程: 是一種用戶態的輕量級線程,協程的調度完全由用戶控制。協程擁有自己的寄存器上下文和棧。協程調度時,將寄存器上下文和棧保存到其他地方,在切回來的時候,恢復先前保存的寄存器上下文和棧,直接操中棧則基本沒有內核切換的開銷,可以不加鎖的訪問全局變量,所以上下文的切換非常快。
101.Python異步使用場景有那些?
異步的使用場景:
1、 不涉及共享資源,獲對共享資源只讀,即非互斥操作
2、 沒有時序上的嚴格關系
3、 不需要原子操作,或可以通過其他方式控制原子性
4、 常用于IO操作等耗時操作,因為比較影響客戶體驗和使用性能
5、 不影響主線程邏輯
102.多線程共同操作同一個數據互斥鎖同步?
import threading
import time
class MyThread(threading.Thread):
def run(self):
global num
time.sleep(1)
if mutex.acquire(1):
num +=1
msg = self.name + 'set num to ' +str(num)
print msg
mutex.release()
num = 0
mutex = threading.Lock()
def test():
for i in range(5):
t = MyThread()
t.start()
if __name__=="__main__":
test()
103.什么是多線程競爭?
線程是非獨立的,同一個進程里線程是數據共享的,當各個線程訪問數據資源時會出現競爭狀態即:數據幾乎同步會被多個線程占用,造成數據混亂,即所謂的線程不安全
那么怎么解決多線程競爭問題?---鎖
鎖的好處: 確保了某段關鍵代碼(共享數據資源)只能由一個線程從頭到尾完整地執行能解決多線程資源競爭下的原子操作問題。
鎖的壞處: 阻止了多線程并發執行,包含鎖的某段代碼實際上只能以單線程模式執行,效率就大大地下降了
鎖的致命問題: 死鎖
104.請介紹一下Python的線程同步?
一、 setDaemon(False)
當一個進程啟動之后,會默認產生一個主線程,因為線程是程序執行的最小單位,當設置多線程時,主線程會創建多個子線程,在Python中,默認情況下就是setDaemon(False),主線程執行完自己的任務以后,就退出了,此時子線程會繼續執行自己的任務,直到自己的任務結束。
例子
import threading
import time
def thread():
time.sleep(2)
print('---子線程結束---')
def main():
t1 = threading.Thread(target=thread)
t1.start()
print('---主線程--結束')
if __name__ =='__main__':
main()
#執行結果
---主線程--結束
---子線程結束---
二、 setDaemon(True)
當我們使用setDaemon(True)時,這是子線程為守護線程,主線程一旦執行結束,則全部子線程被強制終止
例子
import threading
import time
def thread():
time.sleep(2)
print(’---子線程結束---')
def main():
t1 = threading.Thread(target=thread)
t1.setDaemon(True)#設置子線程守護主線程
t1.start()
print('---主線程結束---')
if __name__ =='__main__':
main()
#執行結果
---主線程結束--- #只有主線程結束,子線程來不及執行就被強制結束
三、 join(線程同步)
join 所完成的工作就是線程同步,即主線程任務結束以后,進入堵塞狀態,一直等待所有的子線程結束以后,主線程再終止。
當設置守護線程時,含義是主線程對于子線程等待timeout的時間將會殺死該子線程,最后退出程序,所以說,如果有10個子線程,全部的等待時間就是每個timeout的累加和,簡單的來說,就是給每個子線程一個timeout的時間,讓他去執行,時間一到,不管任務有沒有完成,直接殺死。
沒有設置守護線程時,主線程將會等待timeout的累加和這樣的一段時間,時間一到,主線程結束,但是并沒有殺死子線程,子線程依然可以繼續執行,直到子線程全部結束,程序退出。
例子
import threading
import time
def thread():
time.sleep(2)
print('---子線程結束---')
def main():
t1 = threading.Thread(target=thread)
t1.setDaemon(True)
t1.start()
t1.join(timeout=1)#1 線程同步,主線程堵塞1s 然后主線程結束,子線程繼續執行
#2 如果不設置timeout參數就等子線程結束主線程再結束
#3 如果設置了setDaemon=True和timeout=1主線程等待1s后會強制殺死子線程,然后主線程結束
print('---主線程結束---')
if __name__=='__main___':
main()
105.解釋以下什么是鎖,有哪幾種鎖?
鎖(Lock)是python提供的對線程控制的對象。有互斥鎖,可重入鎖,死鎖。
106.什么是死鎖?
若干子線程在系統資源競爭時,都在等待對方對某部分資源解除占用狀態,結果是誰也不愿先解鎖,互相干等著,程序無法執行下去,這就是死鎖。
GIL鎖 全局解釋器鎖(只在cpython里才有)
作用: 限制多線程同時執行,保證同一時間只有一個線程執行,所以cpython里的多線程其實是偽多線程!
所以python里常常使用協程技術來代替多線程,協程是一種更輕量級的線程。
進程和線程的切換時由系統決定,而協程由我們程序員自己決定,而模塊gevent下切換是遇到了耗時操作時才會切換
三者的關系:進程里有線程,線程里有協程。
107.多線程交互訪問數據,如果訪問到了就不訪問了?
怎么避免重讀?
創建一個已訪問數據列表,用于存儲已經訪問過的數據,并加上互斥鎖,在多線程訪問數據的時候先查看數據是否在已訪問的列表中,若已存在就直接跳過。
108.什么是線程安全,什么是互斥鎖?
每個對象都對應于一個可稱為’互斥鎖‘的標記,這個標記用來保證在任一時刻,只能有一個線程訪問該對象。
同一進程中的多線程之間是共享系統資源的,多個線程同時對一個對象進行操作,一個線程操作尚未結束,另一線程已經對其進行操作,導致最終結果出現錯誤,此時需要對被操作對象添加互斥鎖,保證每個線程對該對象的操作都得到正確的結果。
109.說說下面幾個概念:同步,異步,阻塞,非阻塞?
同步: 多個任務之間有先后順序執行,一個執行完下個才能執行。
異步: 多個任務之間沒有先后順序,可以同時執行,有時候一個任務可能要在必要的時候獲取另一個同時執行的任務的結果,這個就叫回調!
阻塞: 如果卡住了調用者,調用者不能繼續往下執行,就是說調用者阻塞了。
非阻塞: 如果不會卡住,可以繼續執行,就是說非阻塞的。
同步異步相對于多任務而言,阻塞非阻塞相對于代碼執行而言。
110.什么是僵尸進程和孤兒進程?怎么避免僵尸進程?
孤兒進程: 父進程退出,子進程還在運行的這些子進程都是孤兒進程,孤兒進程將被init 進程(進程號為1)所收養,并由init 進程對他們完成狀態收集工作。
僵尸進程: 進程使用fork 創建子進程,如果子進程退出,而父進程并沒有調用wait 獲waitpid 獲取子進程的狀態信息,那么子進程的進程描述符仍然保存在系統中的這些進程是僵尸進程。
避免僵尸進程的方法:
1.fork 兩次用孫子進程去完成子進程的任務
2.用wait()函數使父進程阻塞
3.使用信號量,在signal handler 中調用waitpid,這樣父進程不用阻塞
111..python中進程與線程的使用場景?
多進程適合在CPU密集操作(cpu操作指令比較多,如位多的的浮點運算)。
多線程適合在IO密性型操作(讀寫數據操作比多的的,比如爬蟲)
112..線程是并發還是并行,進程是并發還是并行?
線程是并發,進程是并行;
進程之間互相獨立,是系統分配資源的最小單位,同一個線程中的所有線程共享資源。
113.并行(parallel)和并發(concurrency)?
并行: 同一時刻多個任務同時在運行
不會在同一時刻同時運行,存在交替執行的情況。
實現并行的庫有: multiprocessing
實現并發的庫有: threading
程序需要執行較多的讀寫、請求和回復任務的需要大量的IO操作,IO密集型操作使用并發更好。
CPU運算量大的程序,使用并行會更好
concurrent.futures 中ThreadPoolExecutor ProcessPoolExecutor 封裝multiprocessing, threading
114.IO密集型和CPU密集型區別?
IO密集型: 系統運行,大部分的狀況是CPU在等 I/O(硬盤/內存)的讀/寫
CPU密集型: 大部分時間用來做計算,邏輯判斷等CPU動作的程序稱之CPU密集型。
115.python asyncio的原理?
asyncio這個庫就是使用python的yield這個可以打斷保存當前函數的上下文的機制, 封裝好了selector 擺脫掉了復雜的回調關系
網絡編程
116.怎么實現強行關閉客戶端和服務器之間的連接?
117.簡述TCP和UDP的區別以及優缺點?
UDP是面向無連接的通訊協議,UDP數據包括目的端口號和源端口號信息。
優點:UDP速度快、操作簡單、要求系統資源較少,由于通訊不需要連接,可以實現廣播發送
缺點:UDP傳送數據前并不與對方建立連接,對接收到的數據也不發送確認信號,發送端不知道數據是否會正確接收,也不重復發送,不可靠。
TCP是面向連接的通訊協議,通過三次握手建立連接,通訊完成時四次揮手
優點:TCP在數據傳遞時,有確認、窗口、重傳、阻塞等控制機制,能保證數據正確性,較為可靠。
缺點:TCP相對于UDP速度慢一點,要求系統資源較多
118.簡述瀏覽器通過WSGI請求動態資源的過程?
1、瀏覽器發送請求給web服務器;
2、web服務器接收到動態請求后通過wsgi協議調用框架;
3、框架根據請求信息向數據庫獲取動態數據;
4、框架將獲取的動態數據插入模板文件,構成響應體;
5、框架將響應體數據、響應狀態碼和說明、響應頭信息返回給web服務器;
6、web服務器接收到框架提供的數據后將數據按照響應報文的格式編碼發送給瀏覽器;
7、瀏覽器接收到相應數據后,通過解碼并按照http協議格式顯示在界面上。
119.描述用瀏覽器訪問www.baidu.com的過程
瀏覽器訪問百度
1、先要解析出baidu.com對應的地址
1.1 先通過arp獲取默認網關(交換機)的mac地址(mac地址指的是物理地址)(UDP廣播)
1.2 組織數據發送給默認網關(ip是dns服務器的ip,mac是默認網關的mac地址)
1.3 默認網關(交換機)擁有轉發數據的能力,把數據轉發給路由器
1.4 路由器根據自己的路由協議,選擇一個合適的較快的路徑轉發數據給目的網關
1.5 目的網關(dns服務器所在的網關)把數據轉發給dns服務器
1.6 dns服務器查詢解析出baidu.com對應的IP地址,并將它原路返回給請求這個域名的client
2、得到了baidu.com對應的ip地址后,會發送tcp三次握手進行連接
3、使用http協議發送請求數據給web服務器
4、web服務器收到數據請求之后,通過查詢自己的服務器得到相應的結果,原路返回給瀏覽器
5、瀏覽器接收到數據后,通過瀏覽器自己的渲染功能來顯示這個網頁
6、瀏覽器關閉連接,即四次揮手
120.Post和Get請求的區別?
1.GET是從服務器上獲取數據,POST是向服務器傳送數據
2.在客戶端,GET方式在通過URL提交數據,數據在URL中可以看到,POST方式,數據放置在HTML——HEADER內提交
3.對于GET方式,服務器端用Request.QueryString獲取變量的值,對于POST方式,服務器端用Request.Form獲取提交的數據
MORE ?
瀏覽器的GET和POST
接口中的GET和POST
關于安全性
關于編碼
瀏覽器的POST需要發兩個請求嗎?
關于URL的長度
121.列出你知道的HTTP協議的狀態碼,說出表示什么意思?
122.請簡單說一下三次握手和四次揮手?
123.為什么客戶端在TIME-WAIT狀態必須等待2MSL的時間?
1)為了保證客戶端發送的最后一個ACK報文段能夠達到服務器。?這個ACK報文段可能丟失,因而使處在LAST-ACK狀態的服務器收不到確認。服務器會超時重傳FIN+ACK報文段,客戶端就能在2MSL時間內收到這個重傳的FIN+ACK報文段,接著客戶端重傳一次確認,重啟計時器。最好,客戶端和服務器都正常進入到CLOSED狀態。如果客戶端在TIME-WAIT狀態不等待一段時間,而是再發送完ACK報文后立即釋放連接,那么就無法收到服務器重傳的FIN+ACK報文段,因而也不會再發送一次確認報文。這樣,服務器就無法按照正常步驟進入CLOSED狀態。
2)防止已失效的連接請求報文段出現在本連接中。客戶端在發送完最后一個ACK確認報文段后,再經過時間2MSL,就可以使本連接持續的時間內所產生的所有報文段都從網絡中消失。這樣就可以使下一個新的連接中不會出現這種舊的連接請求報文段。
124.說說HTTP和HTTPS區別?
125.談一下HTTP協議以及協議頭部中表示數據類型的字段?
126.HTTP請求方法都有什么?
127.使用Socket套接字需要傳入哪些參數 ?
128.HTTP常見請求頭?
HTTP消息頭是在,客戶端請求(Request)或服務器響應(Response)時傳遞的,位請求或響應的第一行,HTTP消息體(請求或響應的內容)是其后傳輸。HTTP消息頭,以明文的字符串格式傳送,是以冒號分隔的鍵/值對,如:Accept-Charset: utf-8,每一個消息頭最后以回車符(CR)和換行符(LF)結尾。HTTP消息頭結束后,會用一個空白的字段來標識,這樣就會出現兩個連續的CR-LF。
HTTP消息頭由IANA(The Internet Assigned Numbers Authority,互聯網數字分配機構)來整理和維護。其標準最早來源于RFC 4229。IANA將其整理到了消息頭文檔,文檔中還包括了一些新提出的信息頭。
HTTP消息頭支持自定義, 自定義的專用消息頭一般會添加'X-'前綴。
常用的HTTP請求頭:
Accept可接受的響應內容類型(Content-Types)。Accept: text/plain
Authorization用于表示HTTP協議中需要認證資源的認證信息Authorization: Basic OSdjJGRpbjpvcGVuIANlc2SdDE==
Cache-Control用來指定當前的請求/回復中的,是否使用緩存機制。Cache-Control: no-cache
Cookie由之前服務器通過Set-Cookie(見下文)設置的一個HTTP協議CookieCookie: $Version=1; Skin=new;
Referer表示瀏覽器所訪問的前一個頁面,可以認為是之前訪問頁面的鏈接將瀏覽器帶到了當前頁面。Referer其實是Referrer這個單詞,但RFC制作標準時給拼錯了,后來也就將錯就錯使用Referer了。Referer: http://itbilu.com/nodejs
User-Agent瀏覽器的身份標識字符串User-Agent: Mozilla/……
常用的HTTP響應頭
Status通用網關接口的響應頭字段,用來說明當前HTTP連接的響應狀態。Status: 200 OK
Set-Cookie設置HTTP cookieSet-Cookie: UserID=itbilu; Max-Age=3600; Version=1
Server服務器的名稱Server: nginx/1.6.3
Expires指定一個日期/時間,超過該時間則認為此回應已經過期Expires: Thu, 01 Dec 1994 16:00:00 GMT
129.七層模型?
130.url的形式?
Web
Flask
131.對Flask藍圖(Blueprint)的理解?
藍圖的定義
藍圖 /Blueprint 是Flask應用程序組件化的方法,可以在一個應用內或跨越多個項目共用藍圖。使用藍圖可以極大簡化大型應用的開發難度,也為Flask擴展提供了一種在應用中注冊服務的集中式機制。
藍圖的應用場景:
把一個應用分解為一個藍圖的集合。這對大型應用是理想的。一個項目可以實例化一個應用對象,初始化幾個擴展,并注冊一集合的藍圖。
以URL前綴和/或子域名,在應用上注冊一個藍圖。URL前綴/子域名中的參數即成為這個藍圖下的所有視圖函數的共同的視圖參數(默認情況下)
在一個應用中用不同的URL規則多次注冊一個藍圖。
通過藍圖提供模板過濾器、靜態文件、模板和其他功能。一個藍圖不一定要實現應用或視圖函數。
初始化一個Flask擴展時,在這些情況中注冊一個藍圖。
藍圖的缺點:
不能在應用創建后撤銷注冊一個藍圖而不銷毀整個應用對象。
使用藍圖的三個步驟
1.創建一個藍圖對象
blue = Blueprint("blue",__name__)
2.在這個藍圖對象上進行操作,例如注冊路由、指定靜態文件夾、注冊模板過濾器...
@blue.route('/')
def blue_index():
return "Welcome to my blueprint"
3.在應用對象上注冊這個藍圖對象
app.register_blueprint(blue,url_prefix="/blue")
132.Flask 和 Django 路由映射的區別?
在django中,路由是瀏覽器訪問服務器時,先訪問的項目中的url,再由項目中的url找到應用中url,這些url是放在一個列表里,遵從從前往后匹配的規則。在flask中,路由是通過裝飾器給每個視圖函數提供的,而且根據請求方式的不同可以一個url用于不同的作用。
Django
133.ORM是什么,ORM的優缺點
ORM的全稱是:Object Relational Mapping (對象 關系 映射)
簡單的說,orm是通過使用描述對象和數據之間映射的元數據,將程序中的對象自動持久化到關系數據庫中。
ORM需要解決的問題是,能否把對象的數據直接保存到數據庫中,又能否直接從數據庫中拿到一個對象?要想做到上面兩點,則必須要有映射關系。
ORM的優缺點
優點:
orm的技術特點,提高了開發效率。可以自動對實體Entity對象與數據庫中的Table進行字段與屬性的映射;不用直接SQL編碼,能夠像操作對象一樣從數據庫中獲取數據
缺點:
orm會犧牲程序的執行效率和會固定思維模式,在從系統結構上來看,采用orm的系統多是多層系統的,系統的層次太多,效率就會降低,orm是一種完全面向對象的做法,所以面向對象的做法也會對性能產生一定的影響。
134.查找 Django 項目中的性能瓶頸
django-debug-toolbar or Django-silk
該工具能檢測出查詢操作都來自何處。從而能檢測出到以下瓶頸:
頁面中的重復查詢
ORM 調用引起的查詢操作次數比預想的多
查詢很慢
針對查詢操作較多的頁面進行優化提速 推薦看 Django 官方的數據庫優化文檔
使用 Memcached 或 Redis 對查詢進行緩存
壓縮 HTML、CSS 和 JavaScript
135.什么是wsgi,uwsgi,uWSGI?
WSGI:
web服務器網關接口,是一套協議。用于接收用戶請求并將請求進行初次封裝,然后將請求交給web框架。
實現wsgi協議的模塊:wsgiref,本質上就是編寫一socket服務端,用于接收用戶請求(django)
werkzeug,本質上就是編寫一個socket服務端,用于接收用戶請求(flask)
uwsgi:
與WSGI一樣是一種通信協議,它是uWSGI服務器的獨占協議,用于定義傳輸信息的類型。
uWSGI:
是一個web服務器,實現了WSGI的協議,uWSGI協議,http協議
136.Django、Flask、Tornado的對比?
1、 Django走的大而全的方向,開發效率高。它的MTV框架,自帶的ORM,admin后臺管理,自帶的sqlite數據庫和開發測試用的服務器,給開發者提高了超高的開發效率。
重量級web框架,功能齊全,提供一站式解決的思路,能讓開發者不用在選擇上花費大量時間。
自帶ORM和模板引擎,支持jinja等非官方模板引擎。
自帶ORM使Django和關系型數據庫耦合度高,如果要使用非關系型數據庫,需要使用第三方庫
自帶數據庫管理app
成熟,穩定,開發效率高,相對于Flask,Django的整體封閉性比較好,適合做企業級網站的開發。python web框架的先驅,第三方庫豐富
2、 Flask 是輕量級的框架,自由,靈活,可擴展性強,核心基于Werkzeug WSGI工具 和jinja2 模板引擎
適用于做小網站以及web服務的API,開發大型網站無壓力,但架構需要自己設計
與關系型數據庫的結合不弱于Django,而與非關系型數據庫的結合遠遠優于Django
3、 Tornado走的是少而精的方向,性能優越,它最出名的異步非阻塞的設計方式
Tornado的兩大核心模塊:
iostraem:對非阻塞的socket進行簡單的封裝
ioloop: 對I/O 多路復用的封裝,它實現一個單例
137.CORS 和 CSRF的區別?
什么是CORS?
CORS是一個W3C標準,全稱是“跨域資源共享"(Cross-origin resoure sharing).
它允許瀏覽器向跨源服務器,發出XMLHttpRequest請求,從而客服了AJAX只能同源使用的限制。
什么是CSRF?
CSRF主流防御方式是在后端生成表單的時候生成一串隨機token,內置到表單里成為一個字段,同時,將此串token置入session中。每次表單提交到后端時都會檢查這兩個值是否一致,以此來判斷此次表單提交是否是可信的,提交過一次之后,如果這個頁面沒有生成CSRF token,那么token將會被清空,如果有新的需求,那么token會被更新。
攻擊者可以偽造POST表單提交,但是他沒有后端生成的內置于表單的token,session中沒有token都無濟于事。
138.Session,Cookie,JWT的理解
為什么要使用會話管理
眾所周知,HTTP協議是一個無狀態的協議,也就是說每個請求都是一個獨立的請求,請求與請求之間并無關系。但在實際的應用場景,這種方式并不能滿足我們的需求。舉個大家都喜歡用的例子,把商品加入購物車,單獨考慮這個請求,服務端并不知道這個商品是誰的,應該加入誰的購物車?因此這個請求的上下文環境實際上應該包含用戶的相關信息,在每次用戶發出請求時把這一小部分額外信息,也做為請求的一部分,這樣服務端就可以根據上下文中的信息,針對具體的用戶進行操作。所以這幾種技術的出現都是對HTTP協議的一個補充,使得我們可以用HTTP協議+狀態管理構建一個的面向用戶的WEB應用。
Session 和Cookie的區別
這里我想先談談session與cookies,因為這兩個技術是做為開發最為常見的。那么session與cookies的區別是什么?個人認為session與cookies最核心區別在于額外信息由誰來維護。利用cookies來實現會話管理時,用戶的相關信息或者其他我們想要保持在每個請求中的信息,都是放在cookies中,而cookies是由客戶端來保存,每當客戶端發出新請求時,就會稍帶上cookies,服務端會根據其中的信息進行操作。
當利用session來進行會話管理時,客戶端實際上只存了一個由服務端發送的session_id,而由這個session_id,可以在服務端還原出所需要的所有狀態信息,從這里可以看出這部分信息是由服務端來維護的。
除此以外,session與cookies都有一些自己的缺點:
cookies的安全性不好,攻擊者可以通過獲取本地cookies進行欺騙或者利用cookies進行CSRF攻擊。使用cookies時,在多個域名下,會存在跨域問題。
session 在一定的時間里,需要存放在服務端,因此當擁有大量用戶時,也會大幅度降低服務端的性能,當有多臺機器時,如何共享session也會是一個問題.(redis集群)也就是說,用戶第一個訪問的時候是服務器A,而第二個請求被轉發給了服務器B,那服務器B如何得知其狀態。實際上,session與cookies是有聯系的,比如我們可以把session_id存放在cookies中的。
JWT是如何工作的
首先用戶發出登錄請求,服務端根據用戶的登錄請求進行匹配,如果匹配成功,將相關的信息放入payload中,利用算法,加上服務端的密鑰生成token,這里需要注意的是secret_key很重要,如果這個泄露的話,客戶端就可以隨機篡改發送的額外信息,它是信息完整性的保證。生成token后服務端將其返回給客戶端,客戶端可以在下次請求時,將token一起交給服務端,一般是說我們可以將其放在Authorization首部中,這樣也就可以避免跨域問題。
139.簡述Django請求生命周期
一般是用戶通過瀏覽器向我們的服務器發起一個請求(request),這個請求會去訪問視圖函數,如果不涉及到數據調用,那么這個時候視圖函數返回一個模板也就是一個網頁給用戶)
視圖函數調用模型毛模型去數據庫查找數據,然后逐級返回,視圖函數把返回的數據填充到模板中空格中,最后返回網頁給用戶。
1.wsgi ,請求封裝后交給web框架(Flask,Django)
2.中間件,對請求進行校驗或在請求對象中添加其他相關數據,例如:csrf,request.session
3.路由匹配 根據瀏覽器發送的不同url去匹配不同的視圖函數
4.視圖函數,在視圖函數中進行業務邏輯的處理,可能涉及到:orm,templates
5.中間件,對響應的數據進行處理
6.wsgi,將響應的內容發送給瀏覽器
140.用的restframework完成api發送時間時區
當前的問題是用django的rest framework模塊做一個get請求的發送時間以及時區信息的api
class getCurrenttime(APIView):
def get(self,request):
local_time = time.localtime()
time_zone =settings.TIME_ZONE
temp = {'localtime':local_time,'timezone':time_zone}
return Response(temp)
141.nginx,tomcat,apach到都是什么?
Nginx(engine x)是一個高性能的HTTP和反向代理服務器,也是 一個IMAP/POP3/SMTP服務器,工作在OSI七層,負載的實現方式:輪詢,IP_HASH,fair,session_sticky.
Apache HTTP Server是一個模塊化的服務器,源于NCSAhttpd服務器
Tomcat 服務器是一個免費的開放源代碼的Web應用服務器,屬于輕量級應用服務器,是開發和調試JSP程序的首選。
142.請給出你熟悉關系數據庫范式有哪些,有什么作用?
在進行數據庫的設計時,所遵循的一些規范,只要按照設計規范進行設計,就能設計出沒有數據冗余和數據維護異常的數據庫結構。
數據庫的設計的規范有很多,通常來說我們在設是數據庫時只要達到其中一些規范就可以了,這些規范又稱之為數據庫的三范式,一共有三條,也存在著其他范式,我們只要做到滿足前三個范式的要求,就能設陳出符合我們的數據庫了,我們也不能全部來按照范式的要求來做,還要考慮實際的業務使用情況,所以有時候也需要做一些違反范式的要求。
1.數據庫設計的第一范式(最基本),基本上所有數據庫的范式都是符合第一范式的,符合第一范式的表具有以下幾個特點:
數據庫表中的所有字段都只具有單一屬性,單一屬性的列是由基本的數據類型(整型,浮點型,字符型等)所構成的設計出來的表都是簡單的二比表
2.數據庫設計的第二范式(是在第一范式的基礎上設計的),要求一個表中只具有一個業務主鍵,也就是說符合第二范式的表中不能存在非主鍵列對只對部分主鍵的依賴關系
3.數據庫設計的第三范式,指每一個非主屬性既不部分依賴與也不傳遞依賴于業務主鍵,也就是第二范式的基礎上消除了非主屬性對主鍵的傳遞依賴
143.簡述QQ登陸過程
qq登錄,在我們的項目中分為了三個接口,
第一個接口是請求qq服務器返回一個qq登錄的界面;
第二個接口是通過掃碼或賬號登陸進行驗證,qq服務器返回給瀏覽器一個code和state,利用這個code通過本地服務器去向qq服務器獲取access_token覆返回給本地服務器,憑借access_token再向qq服務器獲取用戶的openid(openid用戶的唯一標識)
第三個接口是判斷用戶是否是第一次qq登錄,如果不是的話直接登錄返回的jwt-token給用戶,對沒有綁定過本網站的用戶,對openid進行加密生成token進行綁定
144.項目中日志的作用
一、日志相關概念
1.日志是一種可以追蹤某些軟件運行時所發生事件的方法
2.軟件開發人員可以向他們的代碼中調用日志記錄相關的方法來表明發生了某些事情
3.一個事件可以用一個包含可選變量數據的消息來描述
4.此外,事件也有重要性的概念,這個重要性也可以被成為嚴重性級別(level)
二、日志的作用
1.通過log的分析,可以方便用戶了解系統或軟件、應用的運行情況;
2.如果你的應用log足夠豐富,可以分析以往用戶的操作行為、類型喜好,地域分布或其他更多信息;
3.如果一個應用的log同時也分了多個級別,那么可以很輕易地分析得到該應用的健康狀況,及時發現問題并快速定位、解決問題,補救損失。
4.簡單來講就是我們通過記錄和分析日志可以了解一個系統或軟件程序運行情況是否正常,也可以在應用程序出現故障時快速定位問題。不僅在開發中,在運維中日志也很重要,日志的作用也可以簡單。總結為以下幾點:
1.程序調試
2.了解軟件程序運行情況,是否正常
3,軟件程序運行故障分析與問題定位
4,如果應用的日志信息足夠詳細和豐富,還可以用來做用戶行為分析
145.django中間件的使用?
Django在中間件中預置了六個方法,這六個方法的區別在于不同的階段執行,對輸入或輸出進行干預,方法如下:
1.初始化:無需任何參數,服務器響應第一個請求的時候調用一次,用于確定是否啟用當前中間件
def __init__():
pass
2.處理請求前:在每個請求上調用,返回None或HttpResponse對象。
def process_request(request):
pass
3.處理視圖前:在每個請求上調用,返回None或HttpResponse對象。
def process_view(request,view_func,view_args,view_kwargs):
pass
4.處理模板響應前:在每個請求上調用,返回實現了render方法的響應對象。
def process_template_response(request,response):
pass
5.處理響應后:所有響應返回瀏覽器之前被調用,在每個請求上調用,返回HttpResponse對象。
def process_response(request,response):
pass
6.異常處理:當視圖拋出異常時調用,在每個請求上調用,返回一個HttpResponse對象。
def process_exception(request,exception):
pass
146.談一下你對uWSGI和nginx的理解?
1.uWSGI是一個Web服務器,它實現了WSGI協議、uwsgi、http等協議。Nginx中HttpUwsgiModule的作用是與uWSGI服務器進行交換。WSGI是一種Web服務器網關接口。它是一個Web服務器(如nginx,uWSGI等服務器)與web應用(如用Flask框架寫的程序)通信的一種規范。
要注意WSGI/uwsgi/uWSGI這三個概念的區分。
WSGI是一種通信協議。
uwsgi是一種線路協議而不是通信協議,在此常用于在uWSGI服務器與其他網絡服務器的數據通信。
uWSGI是實現了uwsgi和WSGI兩種協議的Web服務器。
nginx 是一個開源的高性能的HTTP服務器和反向代理:
1.作為web服務器,它處理靜態文件和索引文件效果非常高
2.它的設計非常注重效率,最大支持5萬個并發連接,但只占用很少的內存空間
3.穩定性高,配置簡潔。
4.強大的反向代理和負載均衡功能,平衡集群中各個服務器的負載壓力應用
147.Python中三大框架各自的應用場景?
django:主要是用來搞快速開發的,他的亮點就是快速開發,節約成本,,如果要實現高并發的話,就要對django進行二次開發,比如把整個笨重的框架給拆掉自己寫socket實現http的通信,底層用純c,c++寫提升效率,ORM框架給干掉,自己編寫封裝與數據庫交互的框架,ORM雖然面向對象來操作數據庫,但是它的效率很低,使用外鍵來聯系表與表之間的查詢;
flask: 輕量級,主要是用來寫接口的一個框架,實現前后端分離,提考開發效率,Flask本身相當于一個內核,其他幾乎所有的功能都要用到擴展(郵件擴展Flask-Mail,用戶認證Flask-Login),都需要用第三方的擴展來實現。比如可以用Flask-extension加入ORM、文件上傳、身份驗證等。Flask沒有默認使用的數據庫,你可以選擇MySQL,也可以用NoSQL。
其WSGI工具箱用Werkzeug(路由模塊),模板引擎則使用Jinja2,這兩個也是Flask框架的核心。
Tornado: Tornado是一種Web服務器軟件的開源版本。Tornado和現在的主流Web服務器框架(包括大多數Python的框架)有著明顯的區別:它是非阻塞式服務器,而且速度相當快。得利于其非阻塞的方式和對epoll的運用,Tornado每秒可以處理數以千計的連接因此Tornado是實時Web服務的一個理想框架
148.Django中哪里用到了線程?哪里用到了協程?哪里用到了進程?
1.Django中耗時的任務用一個進程或者線程來執行,比如發郵件,使用celery.
2.部署django項目是時候,配置文件中設置了進程和協程的相關配置。
149.有用過Django REST framework嗎?
Django REST framework是一個強大而靈活的Web API工具。使用RESTframework的理由有:
Web browsable API對開發者有極大的好處
包括OAuth1a和OAuth2的認證策略
支持ORM和非ORM數據資源的序列化
全程自定義開發--如果不想使用更加強大的功能,可僅僅使用常規的function-based views額外的文檔和強大的社區支持
150.對cookies與session的了解?他們能單獨用嗎?
Session采用的是在服務器端保持狀態的方案,而Cookie采用的是在客戶端保持狀態的方案。但是禁用Cookie就不能得到Session。因為Session是用Session ID來確定當前對話所對應的服務器Session,而Session ID是通過Cookie來傳遞的,禁用Cookie相當于SessionID,也就得不到Session。
爬蟲
測試
151.測試工具
unittest:一個通用的測試框架
doctest:一個更簡單的模塊,是為檢查文檔而設計的,同時非常適合用來編寫單元測試。
locust: 性能測試工具
mock: (Python3 標準庫) mock和patch。
factoryboy, Python測試fixtures(setup和teardown)替代庫。 faker 生成多種偽數據。
數據結構
基礎
152.紅黑樹
紅黑樹與AVL的比較:
AVL是嚴格平衡樹,因此在增加或者刪除節點的時候,根據不同情況,旋轉的次數比紅黑樹要多;
紅黑是用非嚴格的平衡來換取增刪節點時候旋轉次數的降低;
所以簡單說,如果你的應用中,搜索的次數遠遠大于插入和刪除,那么選擇AVL,如果搜索,插入刪除次數幾乎差不多,應該選擇RB。
實戰
算法題直接刷leetcode即可
153.基本排序算法匯總(桶排序,歸并,快排,希爾,插入,選擇,冒泡)
歸并排序
def merge_sort(arr1):
if len(arr1) < 2:
return arr1
half = int(len(arr1) / 2)
left_arr1 = merge_sort(arr1[:half])
right_arr1 = merge_sort(arr1[half:])
return merge(left_arr1, right_arr1)
def merge(left, right):
result = []
while left and right:
result.append(left.pop(0) if left[0] <= right[0] else right.pop(0))
result.extend(left)
result.extend(right)
return result
快速
def quick_sort(arr1):
if len(arr1) < 2:
return arr1
else:
pivot = arr1[0]
less = [i for i in arr1[1:] if i < pivot]
greater = [j for j in arr1[1:] if j >= pivot]
return quick_sort(less) + [pivot] + quick_sort(greater)
插入
def insert_sort(relist):
len_ = len(relist)
for i in range(1,len_):
for j in range(i):
if relist[i] < relist[j]:
relist.insert(j,relist[i])
relist.pop(i+1)
break
return relist
冒泡
def bubble_sort(arr1):
for i in range(len(arr1)):
for j in range(len(arr1[1:])):
if arr1[i] < arr1[j]:
arr1[i], arr1[j] = arr1[j], arr1[i]
return arr1
154.數組中出現次數超過一半的數字-Python版
# -*- coding:utf-8 -*-
class Solution:
def more_than_half(self, numbers):
# write code here
dict = {}
for num in numbers:
if num not in dict:
dict[num] = 1
else:
dict[num]+=1
if dict[num] > len(numbers)/2:
return num
return 0
155.求100以內的質數
156.無重復字符的最長子串-Python實現
class Solution(object):
def lengthOfLongestSubstring(self, s):
res = 0;i = 0; val = ""
for j in range(len(s)):
if s[j] not in s[i:j]:
res = max(res,j+1-i)
else:
i += s[i:j].index(s[j]) + 1
return res
157.通過2個5/6升得水壺從池塘得到3升水
158.什么是MD5加密,有什么特點?
159.什么是對稱加密和非對稱加密
160.如何判斷單向鏈表中是否有環?
# 快慢指針
class Solution(object):
def hasCycle(self, head):
if(head == None or head.next == None):
return False
node1 = head
node2 = head.next
while(node1 != node2):
if(node2 == None or node2.next == None):
return False
node1 = node1.next
node2 = node2.next.next
return True
161.斐波那契數列
def fib();
a, b = 0, 1
while true:
yield a
a, b = b, a+b
from itertools import islice
print list(islice(fib(), 5))
162.如何翻轉一個單鏈表?
class Solution(object):
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
# 申請兩個節點,pre和 cur,pre指向None
pre = None
cur = head
# 遍歷鏈表,while循環里面的內容其實可以寫成一行
# 這里只做演示,就不搞那么騷氣的寫法了
while cur:
# 記錄當前節點的下一個節點
tmp = cur.next
# 然后將當前節點指向pre
cur.next = pre
# pre和cur節點都前進一位
pre = cur
cur = tmp
return pre
163.兩數之和 Two Sum
class Solution(object):
def twoSum(self, nums, target):
_dict = {}
for i, m in enumerate(nums):
if _dict.get(target - m) is not None:
return [_dict.get(target - m), i]
_dict[m] = i
164.搜索旋轉排序數組 Search in Rotated Sorted Array
165.Python實現一個Stack的數據結構
166.寫一個二分查找
def binary_chop(alist, data):
"""
非遞歸解決二分查找
"""
n = len(alist)
first = 0
last = n - 1
while first <= last:
mid = (last+first)//2
if alist[mid] > data:
last = mid - 1
elif alist[mid] < data:
first = mid + 1
else:
return True
return False
def binary_chop2(alist, data):
"""
遞歸解決二分查找
"""
n = len(alist)
if n < 1:
return False
mid = n // 2
if alist[mid] > data:
return binary_chop2(alist[0:mid], data)
elif alist[mid] < data:
return binary_chop2(alist[mid+1:], data)
else:
return True
if __name__ == "__main__":
lis = [2,4, 5, 12, 14, 23]
if binary_chop(lis, 12):
print('ok')
else:
print('false')
167.set 用 in 時間復雜度是多少,為什么?
168.列表中有n個正整數范圍在[0,1000],進行排序;
總結
以上是生活随笔為你收集整理的我python写的闭包为什么效率很低_GitHub - llzhi001/interview_python_practice: interview 面试题 CS-Notes之ME-技术总结...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python自带的idle优点_pyth
- 下一篇: python人工智能要学什么_为什么学人