簡體   English   中英

python:class vs tuple巨大的內存開銷(?)

[英]python: class vs tuple huge memory overhead (?)

我在元組/列表中存儲了大量復雜數據,但更喜歡使用小包裝類來使數據結構更容易理解,例如

class Person:
    def __init__(self, first, last):
        self.first = first
        self.last = last

p = Person('foo', 'bar')
print(p.last)
...

會優先於

p = ['foo', 'bar']
print(p[1])
...

然而 ,似乎有一個可怕的內存開銷:

l = [Person('foo', 'bar') for i in range(10000000)]
# ipython now taks 1.7 GB RAM

del l
l = [('foo', 'bar') for i in range(10000000)]
# now just 118 MB RAM

為什么? 我有沒有想到的任何明顯的替代解決方案?

謝謝!

(我知道,在這個例子中,'wrapper'類看起來很傻。但是當數據變得更復雜和嵌套時,它會更有用)

正如其他人在他們的答案中所說,你必須生成不同的對象才能進行比較。

那么,讓我們比較一些方法。

tuple

l = [(i, i) for i in range(10000000)]
# memory taken by Python3: 1.0 GB

class Person

class Person:
    def __init__(self, first, last):
        self.first = first
        self.last = last

l = [Person(i, i) for i in range(10000000)]
# memory: 2.0 GB

namedtupletuple + __slots__

from collections import namedtuple
Person = namedtuple('Person', 'first last')

l = [Person(i, i) for i in range(10000000)]
# memory: 1.1 GB

namedtuple基本上是一個擴展tuple的類,並為所有命名字段使用__slots__ ,但它添加了字段getter和一些其他幫助方法(如果使用verbose=True調用,則可以看到生成的確切代碼)。

class Person + __slots__

class Person:
    __slots__ = ['first', 'last']
    def __init__(self, first, last):
        self.first = first
        self.last = last

l = [Person(i, i) for i in range(10000000)]
# memory: 0.9 GB

這是上面的namedtuple的精簡版。 一個明顯的贏家,甚至比純元組更好。

使用__slots__減少內存占用(在我的測試中從1.7 GB到625 MB),因為每個實例不再需要持有dict來存儲屬性。

class Person:
    __slots__ = ['first', 'last']
    def __init__(self, first, last):
        self.first = first
        self.last = last

缺點是您不能再在創建實例后向其添加屬性; 該類僅為__slots__屬性中列出的屬性提供內存。

除了關閉__dict____weakref__之外,還有另一種方法可以通過關閉對循環垃圾收集的支持來減少對象占用的內存量。 它在庫記錄類中實現

$ pip install recordclass

>>> import sys
>>> from recordclass import dataobject, make_dataclass

創建類:

class Person(dataobject):
   first:str
   last:str

要么

>>> Person = make_dataclass('Person', 'first last')

結果:

>>> print(sys.getsizeof(Person(100,100)))
32

對於基於__slot__的類,我們有:

class Person:
    __slots__ = ['first', 'last']
    def __init__(self, first, last):
        self.first = first
        self.last = last

>>> print(sys.getsizeof(Person(100,100)))
56

結果,可以更節省存儲器。

對於基於數據dataobject的:

l = [Person(i, i) for i in range(10000000)]
memory size: 681 Mb

對於基於__slots__的:

  l = [Person(i, i) for i in range(10000000)]
  memory size: 921 Mb

在第二個示例中,您只創建一個對象,因為元組是常量。

>>> l = [('foo', 'bar') for i in range(10000000)]
>>> id(l[0])
4330463176
>>> id(l[1])
4330463176

類具有開銷,屬性保存在字典中。 因此,命名元組只需要一半的內存。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM