1. 程式人生 > 實用技巧 >Python面試題

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引入了一個記憶體池機制,用於管理對小塊記憶體的申請和釋放。