標籤:python解譯器 number 刪除 tac word http stack display ike
1. 解釋什麼是棧溢出,在什麼情況下可能出現。
棧溢出是由於C語言系列沒有內建檢查機制來確保複製到緩衝區的資料不得大於緩衝區的大小,因此當這個資料足夠大的時候,將會溢出緩衝區的範圍。
在Python中,函數調用是通過棧(stack)這種資料結構實現的,每當進入一個函數調用,棧就會加一層棧幀,每當函數返回,棧就會減一層棧幀。由於棧的大小不是無限的,所以,遞迴調用的次數過多,會導致棧溢出。
以上內容來自百度百科。https://baike.baidu.com/item/%E6%A0%88%E6%BA%A2%E5%87%BA/8538051?fr=aladdin
棧溢出的幾種情況:
- 局部數組過大,當函數內部的數組過大時,有可能導致堆疊溢位。
- 遞迴調用層次太多。遞迴函式在運行時會執行壓棧操作,當壓棧次數太多時,也會導致堆疊溢位。
- 指標或數組越界。這種情況最常見,例如進行字串拷貝,或處理使用者輸入等等。
以上內容來自,22294291/
2.簡述Cpython的記憶體管理機制
Python和其他進階程式設計語言,如Java、Ruby或JavaScript等一樣,有自動記憶體管理機制。所以許多程式開發人員沒有過多地關注記憶體管理,但是這可能會導致更多的記憶體開銷和記憶體流失。這篇文章是關於CPython(Python解譯器)是如何管理對象的生命週期的深度剖析,文章是我在GitHub上的 vprof 工程中記錄來的,希望對大家有協助。
引用計數
每一個Python對象都有一個引用計數器----用於記錄有多少其他對象指向(引用)這個對象。它儲存在變數 refcnt 中,並通過調用C宏Py_INCREF實現引用計數增加和Py_DECREF實現引用計數減少的操作。 Py_DECREF更複雜點,當引用計數器到零時,它會運行該對象的釋放函數,回收該類型的對象。
通常以下兩種情況你需要考慮這個宏定義:實現自己建立資料結構,或者修改已經存在的Python C API。如果你使用Python內建的資料結構,那麼不需要任何操作。
如果想不增加引用計數,可以使用弱引用或 weakrefs 引用對象。 Weakrefs對於實現緩衝和代理非常有用。
記憶體回收(GC)
引用計數是在Python 2.0之前管理對象生命週期的唯一方法。它有一個弱點,它不能刪除循環參考的對象。 循環參考的最簡單的例子是對象引用自身。
通常情況下,可以避免使用循環參考對象,但是有時是不可避免的(例如:長時間啟動並執行程式)。
為瞭解決這個問題,Python 2.0引入了新的記憶體回收機制。 新GC與其他語言運行時(如JVM和CLR)的GC的主要區別在於,它僅用於尋找存在引用計數的循環參考。
循環參考只能由容器物件建立,因此Python GC不會跟蹤整數,字串等類型。
GC將對象分為3代,每一代對象都有一個計數器和一個閾值。當對象被建立時,閾值會被自動地指派為0,也就是第0代對象。當計數器大於某個閥值,GC就會運行在當前對象代上,回收該對象。沒被回收的對象會被移至下一代,並且將相應的計數器複位。下一代的對象保留在下一代。
在Python 3.4之前,GC有一個致命缺點----每個對象重載了del__()方法,因為每個對象都可以相互引用,所以GC不知道該調用那個對象的__del()方法,這會導致GC直接跳過這些對象。具體詳細資料可以參考 gc.garbage並且循環參考需要編程人員手動打破。
Python3.4介紹了一種最終的解決方案finalization approach ,現在的GC可以打破對象的循環參考,而不在使用gc.garbage介紹的方法去回收對象。
此外,值得一提的是,如果你確定你的代碼沒有建立循環參考(或者你不關心記憶體管理),那麼你可以只依賴引用計數器自動管理記憶體,而不使用GC去管理記憶體。
以上內容來自:,https://python.freelycode.com/contribution/detail/511
英文原文:https://medium.com/@nvdv/cpython-memory-management-479e6cd86c9#.sbvb0py87
3.請列舉你知道的Python的魔法方法及用途。__init__
構造器,當一個執行個體被建立的時候調用的初始化方法
__new__
- __new__ 是在一個對象執行個體化的時候所調用的第一個方法
- 它的第一個參數是這個類,其他的參數是用來直接傳遞給 __init__ 方法
- __new__ 決定是否要使用該 __init__ 方法,因為 __new__ 可以調用其他類的構造方法或者直接返回別的執行個體對象來作為本類的執行個體,如果 __new__ 沒有返回執行個體對象,則 __init__ 不會被調用
- __new__ 主要是用於繼承一個不可變的類型比如一個 tuple 或者 string
__call__
允許一個類的執行個體像函數一樣被調用
__del__
析構器,當一個執行個體被銷毀的時候調用的方法
__len__(self): 定義當被 len() 調用時的行為
__repr__(self): 定義當被 repr() 調用時的行為
__str__(self): 定義當被 str() 調用時的行為
__bytes__(self):定義當被 bytes() 調用時的行為
__hash__(self): 定義當被 hash() 調用時的行為
__bool__(self): 定義當被 bool() 調用時的行為,應該返回 True 或 False
4. 已知以下list:
list1 = [
{
"mm": 2,
},{
"mm": 1,
},{
"mm": 4,
},{
"mm": 3,
},{
"mm": 3,
}
]
4.1 把list1中的元素按mm的值排序。
首先說函數sorted的具體用法:
(1).Python2.x:sorted(iterable, cmp=None, key=None, reverse=False)
,Python3.x:sorted(iterable, /, *, key=None, reverse=False),Python3.x和Python2.x的sorted函數有點不太一樣,少了cmp參數。
key接受一個函數,這個函數只接受一個元素,預設為None
reverse是一個布爾值。如果設定為True,列表元素將被倒序排列,預設為False
著重介紹key的作用原理:
key指定一個接收一個參數的函數,這個函數用於從每個元素中提取一個用於比較的關鍵字。預設值為None 。
(2).sorted() 函數對所有可迭代的對象進行排序操作。
(3).對於 元群組類型的列表比如
list2=[(‘b‘,4),(‘a‘,0),(‘c‘,2),(‘d‘,3)]
排序的方法是使用lambda然後擷取需要排的元素的下標即可。
print(sorted(list2,key=lambda x:x[0]))
而本題有點麻煩 裡面是字典類型所以我們需要通過以下方式擷取
答案 :
sorted(list1,key=lambda x:x.items()[0][1])
或者
sorted(list1,key=lambda x:x[‘mm‘]))
或者用 operator 函數來加快速度, 上面排序等價於
from operator import itemgetter
print(sorted(list1,key=itemgetter(‘mm‘)))
4.2 擷取list1中第一個mm值等於x的元素。
4.3 刪除list1中所有mm等於x的元素,且不對list重新賦值。
4.4 取出list1中mm最大的元素,不能排序。
後續
python近期遇到的一些面試問題(二)