Python面試題
is 和 ==的區別
is: 比較物件的id值,也就是是否指向同一個記憶體地址
==: 比較物件的值是否相等,預設會呼叫物件的eq()方法
python內建資料結構
列表、字典、字串、集合、元組
變數作用域
LEGB
L: local函式內部作用域
E: enclosing函式內部與內嵌函式之間
G: global全域性作用域
B: build-in 內建作用域
var_a=1 var_b=10 var_c=100 def outer(): var_a=2 var_b=20 def inner(): var_a=3 print(var_a) # L local 優先使用本地 print(var_b) # E enclosing 本地沒有找巢狀作用域 print(var_c) # G global 全域性作用域 print(__name__,max,min,id) # B built-in 找內建作用域 inner() outer()
super舉例
class Base: def __init__(self): print('Base.__init__') class A(Base): def __init__(self): super().__init__() print('A.__init__') class B(Base): def __init__(self): super().__init__() print('B.__init__') class C(A,B): def __init__(self): super().__init__() # Only one call to super() here print('C.__init__') >>> c = C() Base.__init__ B.__init__ A.__init__ C.__init__ >>> C.__mro__ (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Base'>, <class 'object'>)
單例
class Singleton2(object): def __new__(cls, *args, **kwargs): if not hasattr(cls, '_instance'): cls._instance = super(Singleton2, cls).__new__(cls, *args, **kwargs) return cls._instance class foo(Singleton2): pass foo1 = foo() foo2 = foo() print (foo1 is foo2)
字典按值排序
>>> a={"a":2, "v": 1, "ds": 100}
>>> sorted(a.items(), key=lambda x:x[1])
[('v', 1), ('a', 2), ('ds', 100)]
>>> sorted(a.items(), key=lambda x:x[1], reverse=True)
[('ds', 100), ('a', 2), ('v', 1)]
>>> dict(sorted(a.items(), key=lambda x:x[1], reverse=True))
{'ds': 100, 'a': 2, 'v': 1}
找出列表中相同和不同的元素
list1 = [1,2,3]
list2 = [3,4,5]
set1 = set(list1)
set2 = set(list2)
print(set1 & set2) #相同的
print(set1 ^ set2) #不同的
GIL(global interpreter lock - 全域性直譯器鎖)
並行:多個CPU同時執行多個任務,就好像有兩個程式,這兩個程式是真的在兩個不同的CPU內同時被執行。
併發:CPU交替處理多個任務,還是有兩個程式,但是隻有一個CPU,會交替處理這兩個程式,而不是同時執行,只不過因為CPU執行的速度過快,而會使得人們感到是在“同時”執行,執行的先後取決於各個程式對於時間片資源的爭奪
- 單執行緒: 雙核cpu使用率50%
- 多執行緒:雙核cpu使用率50%
- 多程序:雙核cpu使用率100%
如何解決GIL鎖的問題
1、更換Cpython為Jpython
2、使用多程序完成多執行緒任務
什麼時候會釋放GIL鎖
1、遇到像 i/o操作這種 會有時間空閒情況 造成cpu閒置的情況會釋放Gil
2、會有一個專門ticks進行計數 一旦ticks數值達到100 這個時候釋放Gil鎖 執行緒之間開始競爭Gil鎖(說明:
ticks這個數值可以進行設定來延長或者縮減獲得Gil鎖的執行緒使用cpu的時間)
互斥鎖和GIL鎖的關係
Gil鎖 : 保證同一時刻只有一個執行緒能使用到cpu
互斥鎖 : 多執行緒時,保證修改共享資料時有序的修改,不會產生資料修改混亂
記憶體管理機制
1、引用計數
引用計數是一種非常高效的記憶體管理手段,當一個pyhton物件被引用時其引用計數增加1,當其不再被引用時引用計數減1,當引用計數等於0的時候,物件就被刪除了。
2、垃圾回收
- 引用計數
- 標記清除
標記清除用來解決迴圈引用產生的問題,迴圈引用只有在容器物件才會產生,比如字典,元祖,列表等。首先為了追蹤物件,需要每個容器物件維護兩個額外的指標,用來將容器物件組成一個連結串列,指標分別指向前後兩個容器物件,這樣可以將物件的迴圈引用摘除,就可以得出兩個物件的有效計數。 - 分代回收
隨著你的程式執行,Python直譯器保持對新建立的物件,以及因為引用計數為零而被釋放掉的物件的追蹤。從理論上說,建立==釋放數量應該是這樣子。但是如果存在迴圈引用的話,肯定是建立>釋放數量,當建立數與釋放數量的差值達到規定的閾值的時候,噹噹噹當~分代回收機制就登場啦。
分代回收思想將物件分為三代(generation 0,1,2)
0代表幼年物件,
1代表青年物件,
2代表老年物件。
根據弱代假說(越年輕的物件越容易死掉,老的物件通常會存活更久。)
新生的物件被放入0代,如果該物件在第0代的一次gc垃圾回收中活了下來,那麼它就被放到第1代裡面(它就升級了)。如果第1代裡面的物件在第1代的一次gc垃圾回收中活了下來,它就被放到第2代裡面。
從上一次第0代gc後,如果分配物件的個數減去釋放物件的個數大於threshold0,那麼就會對第0代中的物件進行gc垃圾回收檢查。
從上一次第1代gc後,如果第0代被gc垃圾回收的次數大於threshold1,那麼就會對第1代中的物件進行gc垃圾回收檢查。
從上一次第2代gc後,如果第1代被gc垃圾回收的次數大於threshold2,那麼就會對第2代中的物件進行gc垃圾回收檢查。
gc每一代垃圾回收所觸發的閾值可以自己設定。
3、記憶體池
Python的記憶體機制呈現金字塔形狀,-1,-2層主要有作業系統進行操作
第0層是C中的malloc,free等記憶體分配和釋放函式進行操作
第1層和第2層是記憶體池,有python介面函式,PyMem_Malloc函式實現,當物件小於256k的時由該層直接分配記憶體
第3層是最上層,也就是我們對python物件的直接操作
Python在執行期間會大量地執行malloc和free的操作,頻繁地在使用者態和核心態之間進行切換,這將嚴重影響Python的執行效率。為了加速Python的執行效 率,Python引入了一個記憶體池機制,用於管理對小塊記憶體的申請和釋放。