python申请内存函数_python进阶用法2 【从帮助函数看python内存申请机制】
前言
介紹了四個幫助函數,dir(),help(),type(),id(),通過id()函數進一步分析了python在申請內存方面的效率問題,提到的基本類型有string,list,queue和deque
四個幫助函數
dir()函數
dir()函數是查看函數或模塊內的操作方法都有什么,輸出的是方法列表。
dir('str')
也可以查看自己定義的函數
help()函數
help()函數是查看函數或模塊用途的詳細說明,例:
help('str')
type()函數
這個很簡單了,返回其類型,略
id()函數
對一個對象的引用調用id()函數,可以得到該對象的標識符(dentity).該標識符是一個整數,它保證在該對象的生命周期內是唯一的和恒定的.具有不重疊生命周期的兩個對象具有相同的id()值.
PS: 在CPython實現細節:標識符(dentity)為對象在內存中的地址. 在Python中一切皆對象,變量中存放的是對象的引用.字符串常量和整型常量都是對象.
舉個例子:
>>> a = 1
>>> b=2
>>> c =1
>>> id(a)
1521120064
>>> id(b)
1521120096
>>> id(c)
1521120064
不知道,在看這個dentity的時候,有沒有發現a與c的地址是相同的!!!
從id()函數看python內存地址申請機制
看個例子:(以下內容來源@Unname_Bao 關于python3中整數數組轉bytes的效率問題)
如果還是沒有理解的話,接下來看我本地進行的一個非常簡單的一個演示腳本測試:
import time
t1 = time.time()
astr = 'a'
for x in range(1,2000000):
astr = astr + str(x)
astr
t2 = time.time()
print(t2-t1)
#10.028913259506226
#[Finished in 10.2s]
import time
t1 = time.time()
astr = list('1'*2000000)
for x in range(1,2000000):
astr[x]=str(x)
bstr = str(astr)
t2 = time.time()
print(t2-t1)
#0.8323781490325928
#[Finished in 1.1s]
為什么差距如此之大呢?這就回到了我們最初提到的a,b,當值改變,會重新去申請內存空間(id改變)。在這第一個例子中,我們不停地改變astr的值,astr即不停地申請內存空間,此過程消耗了大量的時間!!!第二個例子中,我們一次申請了夠所有變量使用的內存空間地址,免去了每次申請,所以大大加快了運行速度!!!
感謝@一個閑散之人的閑散更進一步的分析,
影響其效率問題的核心根本在于list到底是基于鏈表的數據結構還是基于線性表的數據結構。線性表的話為了騰出足夠連續空間需要改變表頭的內存位置,也就造成了id的改變,對于鏈表而言,則只需要申請一個結點大小的內存量,沒必要對表頭的內存位置動手腳。
關于list的數據結構,從知乎上get到的結果是線性表形式的數據結構,于是乎我又做了以下3個測試:
1、不提前申請空間的queue
import time
import queue
t1 = time.time()
astr = queue.Queue()
for x in range(1,2000000):
astr.put(str(x))
bstr = str(astr)
t2 = time.time()
print(t2-t1)
# 4.525705337524414
# [Finished in 4.8s]
2、不提前申請空間的deque
import collections
import time
t1 = time.time()
astr = collections.deque()
for x in range(1,2000000):
astr.append(str(x))
bstr = str(astr)
t2 = time.time()
print(t2-t1)
# 0.938164234161377
# [Finished in 1.3s]
3、不提前申請空間的list
import time
t1 = time.time()
astr = []
for x in range(1,2000000):
astr.append(str(x))
bstr = str(astr)
t2 = time.time()
print(t2-t1)
# 0.9456796646118164
# [Finished in 1.2s]
另做個測試:
import collections
import queue
print("Deque ID:")
astr1 = collections.deque()
for x in range(1,5):
astr1.append(str(x))
print(id(astr1))
print("Queue ID:")
astr2 = queue.Queue()
for x in range(1,5):
astr2.put(str(x))
print(id(astr2))
print("list ID:")
astr3 = []
for x in range(1,5):
astr3.append(str(x))
print(id(astr3))
# Deque ID:
# 1206229307464
# 1206229307464
# 1206229307464
# 1206229307464
# Queue ID:
# 1206225595416
# 1206225595416
# 1206225595416
# 1206225595416
# list ID:
# 1206229266760
# 1206229266760
# 1206229266760
# 1206229266760
# [Finished in 0.2s]
queue、deque其實可以很明顯看出,其均是依靠c的鏈表進行開發的(不需要提前申請空間),其地址亦不變化。更改一點之前的錯誤理解,python的list實現不是鏈表,而是動態數組
當我們使用deque時,可以很明顯看到,我們的時間消耗已經差距很小了,與未提前申請空間的list接近一致,但經多次運行,還是可以發現,最快的依舊是已經申請了空間的list,我么進一步去了解queue和deque可以發現其無法提前申請空間(可以理解為其職能分別從一端和兩段進行增加值,減值),及無法像list一樣可以通過list[下標]直接取值,所以綜上所述,list無疑是最快的~
補充,list的擴張空間機制
>>> test = []
>>> test.__sizeof__()
40
>>> test.append('a')
>>> test.__sizeof__()
72
>>> test.append('a')
>>> test.__sizeof__()
72
>>> test.append('a')
>>> test.__sizeof__()
72
>>> test.append('a')
>>> test.__sizeof__()
72
>>> test.append('a')
>>> test.__sizeof__()
104
>>>
參考鏈接:Python中list的內存分配
總結
以上是生活随笔為你收集整理的python申请内存函数_python进阶用法2 【从帮助函数看python内存申请机制】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python 打包成exe 1053_P
- 下一篇: python编程绘图库turtle如何安