亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

python使用__slots__讓你的代碼更加節(jié)省內(nèi)存

 更新時(shí)間:2018年09月05日 09:10:01   作者:david_bj  
如果要限制添加的屬性,例如,Student類只允許添加 name、gender和score 這3個(gè)屬性,就可以利用Python的一個(gè)特殊的slots來實(shí)現(xiàn)。這篇文章主要給大家介紹了關(guān)于python如何使用__slots__讓你的代碼更加節(jié)省內(nèi)存的相關(guān)資料,需要的朋友可以參考下

前言

在默認(rèn)情況下,Python的新類和舊類的實(shí)例都有一個(gè)字典來存儲(chǔ)屬性值。這對(duì)于那些沒有實(shí)例屬性的對(duì)象來說太浪費(fèi)空間了,當(dāng)需要?jiǎng)?chuàng)建大量實(shí)例的時(shí)候,這個(gè)問題變得尤為突出。

因此這種默認(rèn)的做法可以通過在新式類中定義了一個(gè)__slots__屬性從而得到了解決。__slots__聲明中包含若干實(shí)例變量,并為每個(gè)實(shí)例預(yù)留恰好足夠的空間來保存每個(gè)變量,因此沒有為每個(gè)實(shí)例都創(chuàng)建一個(gè)字典,從而節(jié)省空間。

本文主要介紹了關(guān)于python使用__slots__讓你的代碼更加節(jié)省內(nèi)存的相關(guān)內(nèi)容,分享出來供大家參考學(xué)習(xí),下面話不多說了,來一起看看詳細(xì)的介紹吧

現(xiàn)在來說說python中dict為什么比list浪費(fèi)內(nèi)存?

和list相比,dict 查找和插入的速度極快,不會(huì)隨著key的增加而增加;dict需要占用大量的內(nèi)存,內(nèi)存浪費(fèi)多。

而list查找和插入的時(shí)間隨著元素的增加而增加;占用空間小,浪費(fèi)的內(nèi)存很少。

python解釋器是Cpython,這兩個(gè)數(shù)據(jù)結(jié)構(gòu)應(yīng)該對(duì)應(yīng)C的哈希表和數(shù)組。因?yàn)楣1硇枰~外內(nèi)存記錄映射關(guān)系,而數(shù)組只需要通過索引就能計(jì)算出下一個(gè)節(jié)點(diǎn)的位置,所以哈希表占用的內(nèi)存比數(shù)組大,也就是dict比list占用的內(nèi)存更大。

如果想更加詳細(xì)了解,可以查看C的源代碼。python官方鏈接:https://www.python.org/downloads/source/

如下代碼是我從python官方截取的代碼片段:

List 源碼:

typedef struct {
 PyObject_VAR_HEAD
 /* Vector of pointers to list elements. list[0] is ob_item[0], etc. */
 PyObject **ob_item;
 
 /* ob_item contains space for 'allocated' elements. The number
 * currently in use is ob_size.
 * Invariants:
 * 0 <= ob_size <= allocated
 * len(list) == ob_size
 * ob_item == NULL implies ob_size == allocated == 0
 * list.sort() temporarily sets allocated to -1 to detect mutations.
 *
 * Items must normally not be NULL, except during construction when
 * the list is not yet visible outside the function that builds it.
 */
 Py_ssize_t allocated;
} PyListObject;

Dict源碼:

/* PyDict_MINSIZE is the minimum size of a dictionary. This many slots are
 * allocated directly in the dict object (in the ma_smalltable member).
 * It must be a power of 2, and at least 4. 8 allows dicts with no more
 * than 5 active entries to live in ma_smalltable (and so avoid an
 * additional malloc); instrumentation suggested this suffices for the
 * majority of dicts (consisting mostly of usually-small instance dicts and
 * usually-small dicts created to pass keyword arguments).
 */
#define PyDict_MINSIZE 8
 
typedef struct {
 /* Cached hash code of me_key. Note that hash codes are C longs.
 * We have to use Py_ssize_t instead because dict_popitem() abuses
 * me_hash to hold a search finger.
 */
 Py_ssize_t me_hash;
 PyObject *me_key;
 PyObject *me_value;
} PyDictEntry;
 
/*
To ensure the lookup algorithm terminates, there must be at least one Unused
slot (NULL key) in the table.
The value ma_fill is the number of non-NULL keys (sum of Active and Dummy);
ma_used is the number of non-NULL, non-dummy keys (== the number of non-NULL
values == the number of Active items).
To avoid slowing down lookups on a near-full table, we resize the table when
it's two-thirds full.
*/
typedef struct _dictobject PyDictObject;
struct _dictobject {
 PyObject_HEAD
 Py_ssize_t ma_fill; /* # Active + # Dummy */
 Py_ssize_t ma_used; /* # Active */
 
 /* The table contains ma_mask + 1 slots, and that's a power of 2.
 * We store the mask instead of the size because the mask is more
 * frequently needed.
 */
 Py_ssize_t ma_mask;
 
 /* ma_table points to ma_smalltable for small tables, else to
 * additional malloc'ed memory. ma_table is never NULL! This rule
 * saves repeated runtime null-tests in the workhorse getitem and
 * setitem calls.
 */
 PyDictEntry *ma_table;
 PyDictEntry *(*ma_lookup)(PyDictObject *mp, PyObject *key, long hash);
 PyDictEntry ma_smalltable[PyDict_MINSIZE];
};

PyObject_HEAD 源碼:

#ifdef Py_TRACE_REFS
/* Define pointers to support a doubly-linked list of all live heap objects. */
#define _PyObject_HEAD_EXTRA  \
 struct _object *_ob_next;  \
 struct _object *_ob_prev;
 
#define _PyObject_EXTRA_INIT 0, 0,
 
#else
#define _PyObject_HEAD_EXTRA
#define _PyObject_EXTRA_INIT
#endif
 
/* PyObject_HEAD defines the initial segment of every PyObject. */
#define PyObject_HEAD   \
 _PyObject_HEAD_EXTRA  \
 Py_ssize_t ob_refcnt;  \
 struct _typeobject *ob_type;

PyObject_VAR_HEAD 源碼:

/* PyObject_VAR_HEAD defines the initial segment of all variable-size
 * container objects. These end with a declaration of an array with 1
 * element, but enough space is malloc'ed so that the array actually
 * has room for ob_size elements. Note that ob_size is an element count,
 * not necessarily a byte count.
 */
#define PyObject_VAR_HEAD  \
 PyObject_HEAD   \
 Py_ssize_t ob_size; /* Number of items in variable part */

現(xiàn)在知道了dict為什么比list 占用的內(nèi)存空間更大。接下來如何讓你的類更加的節(jié)省內(nèi)存。

其實(shí)有兩種解決方案:

第一種是使用__slots__ ;另外一種是使用Collection.namedtuple 實(shí)現(xiàn)。

首先用標(biāo)準(zhǔn)的方式寫一個(gè)類:

#!/usr/bin/env python

class Foobar(object):
 def __init__(self, x):
 self.x = x

@profile
def main():
 f = [Foobar(42) for i in range(1000000)]

if __name__ == "__main__":
 main()

然后,創(chuàng)建一個(gè)類Foobar(),然后實(shí)例化100W次。通過@profile查看內(nèi)存使用情況。

運(yùn)行結(jié)果:

該代碼共使用了372M內(nèi)存。

接下來通過__slots__代碼實(shí)現(xiàn)該代碼:

#!/usr/bin/env python

class Foobar(object):
 __slots__ = 'x'
 def __init__(self, x):
 self.x = x
@profile
def main():
 f = [Foobar(42) for i in range(1000000)]

if __name__ == "__main__":
 main()

運(yùn)行結(jié)果:

使用__slots__使用了91M內(nèi)存,比使用__dict__存儲(chǔ)屬性值節(jié)省了4倍。

其實(shí)使用collection模塊的namedtuple也可以實(shí)現(xiàn)__slots__相同的功能。namedtuple其實(shí)就是繼承自tuple,同時(shí)也因?yàn)開_slots__的值被設(shè)置成了一個(gè)空tuple以避免創(chuàng)建__dict__。

看看collection是如何實(shí)現(xiàn)的:

collection 和普通創(chuàng)建類方式相比,也節(jié)省了不少的內(nèi)存。所在在確定類的屬性值固定的情況下,可以使用__slots__方式對(duì)內(nèi)存進(jìn)行優(yōu)化。但是這項(xiàng)技術(shù)不應(yīng)該被濫用于靜態(tài)類或者其他類似場(chǎng)合,那不是python程序的精神所在。

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • Numpy(Pandas)刪除全為零的列的方法

    Numpy(Pandas)刪除全為零的列的方法

    這篇文章主要介紹了Numpy(Pandas)刪除全為零的列的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Matplotlib 繪制餅圖解決文字重疊的方法

    Matplotlib 繪制餅圖解決文字重疊的方法

    這篇文章主要介紹了Matplotlib 繪制餅圖解決文字重疊的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • python re模塊匹配貪婪和非貪婪模式詳解

    python re模塊匹配貪婪和非貪婪模式詳解

    這篇文章主要介紹了python re模塊匹配貪婪和非貪婪模式詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • python關(guān)于字典及遍歷的常用方法

    python關(guān)于字典及遍歷的常用方法

    這篇文章主要介紹了python關(guān)于字典及遍歷的常用方法,字典的鍵可以是字符串、整數(shù)、元組或字典。字典的值也可以是字符串、整數(shù),文章圍繞主題展開更多詳細(xì)的內(nèi)容,需要的小伙伴可以參考一下
    2022-06-06
  • pycharm設(shè)置當(dāng)前工作目錄的操作(working directory)

    pycharm設(shè)置當(dāng)前工作目錄的操作(working directory)

    今天小編就為大家分享一篇pycharm設(shè)置當(dāng)前工作目錄的操作(working directory),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-02-02
  • 使用50行Python代碼從零開始實(shí)現(xiàn)一個(gè)AI平衡小游戲

    使用50行Python代碼從零開始實(shí)現(xiàn)一個(gè)AI平衡小游戲

    本文會(huì)為大家展示機(jī)器學(xué)習(xí)專家 Mike Shi 如何用 50 行 Python 代碼創(chuàng)建一個(gè) AI,使用增強(qiáng)學(xué)習(xí)技術(shù),玩耍一個(gè)保持桿子平衡的小游戲。本文給大家?guī)韺?shí)現(xiàn)思路及簡(jiǎn)單代碼,感興趣的朋友跟隨小編一起看看吧
    2018-11-11
  • python圖像和辦公文檔處理總結(jié)

    python圖像和辦公文檔處理總結(jié)

    在本文里我們給大家整理了關(guān)于python圖像和辦公文檔處理的相關(guān)知識(shí)點(diǎn)內(nèi)容以及重點(diǎn)內(nèi)容總結(jié),有需要的朋友們跟著學(xué)習(xí)下。
    2019-05-05
  • 如何基于Python實(shí)現(xiàn)一個(gè)慶祝國(guó)慶節(jié)的小程序

    如何基于Python實(shí)現(xiàn)一個(gè)慶祝國(guó)慶節(jié)的小程序

    這篇文章主要介紹了如何基于Python實(shí)現(xiàn)一個(gè)慶祝國(guó)慶節(jié)的小程序,增加了互動(dòng)選擇祝福語、查詢信息、播放背景音樂及趣味小測(cè)驗(yàn)等功能,使用tkinter增強(qiáng)GUI,提升用戶互動(dòng)體驗(yàn),需要的朋友可以參考下
    2024-09-09
  • Python實(shí)現(xiàn)端口復(fù)用實(shí)例代碼

    Python實(shí)現(xiàn)端口復(fù)用實(shí)例代碼

    這篇文章主要介紹了Python實(shí)現(xiàn)端口復(fù)用實(shí)例代碼,需要的朋友可以參考下
    2014-07-07
  • Python爬蟲文件下載圖文教程

    Python爬蟲文件下載圖文教程

    在本篇內(nèi)容里小編給大家分享的是關(guān)于Python爬蟲文件下載的相關(guān)知識(shí)點(diǎn)內(nèi)容,有需要的朋友們學(xué)習(xí)下。
    2018-12-12

最新評(píng)論