代码之家  ›  专栏  ›  技术社区  ›  Mad Physicist

什么是用于单个引用的有效容器?

  •  1
  • Mad Physicist  · 技术社区  · 5 年前

    我有一个包含统一类型的任意对象的列表:

    items = ['a', 'b', 'c', 'x', 'y', 'z']
    

    我正在扫描列表,并根据一些不重要的条件将对象放在容器中标记它们。假设这是奇怪的指数:

    for i in range(len(items)):
        if i % 2:
            items[i] = (items[i],)
    

    第二次检查将过滤列表以打开标记的项目并删除所有其他内容:

    items = [x[0] for x in items if isinstance(x, tuple)]
    

    这段代码基本上是功能性的。但是,对于非常大的阵列,标记会增加内存使用量,并且自然会占用时间。

    对于这样的东西,最有效的容器是什么?我使用tuple是因为它在我看到的所有容器类中占用的空间最小。有没有更好的方法包装一个单一的参考?

    这个问题是由于 Corroborating 2 large Python dictionaries .

    2 回复  |  直到 5 年前
        1
  •  1
  •   user2357112    5 年前

    为此使用包装器对象本质上是内存效率低下的,因为在64位系统上,每个包装器至少需要40个字节—每个包装器需要8个字节

    • 类型指针,
    • 引用计数,
    • 内容指针,以及

    此最小40字节可通过自定义容器实现:

    class Wrapper(object):
        __slots__ = ('content',)
        def __init__(self, content):
            self.content = content
    

    或与 types.CellType 在Python3.8+上:

    import types
    wrapper = types.CellType(wrapped)
    extracted_content = wrapper.cell_contents
    

    或者在低于3.8的Python版本上创建闭包单元的方法不那么直接:

    def make_wrapper(x):
        return (lambda: x).__closure__[0]
    
    wrapper = make_wrapper(wrapped)
    extracted_content = wrapper.cell_contents
    

    但不涉及包装器的技术将能够实现更低的内存开销。

        2
  •  2
  •   Mad Physicist    5 年前

    我推荐使用布尔列表或元组进行标记。如果需要,可以将其压缩为位图。

    flag = [i%2 for i in range(len(items))]
    

    在第二个过程中,从 items :

    new_items = [x for x, wanted in zip(items, flag) if wanted]
    

    你会继续吗?