python:class vs tuple巨大的内存开销(?)

seb*_*314 10 python tuples class list data-structures

我在元组/列表中存储了大量复杂数据,但更喜欢使用小包装类来使数据结构更容易理解,例如

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

p = Person('foo', 'bar')
print(p.last)
...
Run Code Online (Sandbox Code Playgroud)

会优先于

p = ['foo', 'bar']
print(p[1])
...
Run Code Online (Sandbox Code Playgroud)

然而,似乎有一个可怕的内存开销:

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

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

为什么?我有没有想到的任何明显的替代解决方案?

谢谢!

(我知道,在这个例子中,'wrapper'类看起来很傻.但是当数据变得更复杂和嵌套时,它会更有用)

ran*_*mir 11

正如其他人在他们的答案中所说,你必须生成不同的对象才能进行比较.

那么,让我们比较一些方法.

tuple

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

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
Run Code Online (Sandbox Code Playgroud)

namedtuple(tuple+ __slots__)

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

l = [Person(i, i) for i in range(10000000)]
# memory: 1.1 GB
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

这是namedtuple上面的精简版.一个明显的赢家,甚至比纯元组更好.


che*_*ner 5

使用会__slots__减少内存占用(在我的测试中从1.7 GB到625 MB),因为每个实例不再需要保存dict来存储属性.

class Person:
    __slots__ = ['first', 'last']
    def __init__(self, first, last):
        self.first = first
        self.last = last
Run Code Online (Sandbox Code Playgroud)

缺点是您不能再在创建实例后向其添加属性; 该类仅为属性中列出的__slots__属性提供内存.