【问题标题】:Since Tuples are immutable, why does slicing them make a copy instead of a view?既然元组是不可变的,为什么切片它们会生成副本而不是视图?
【发布时间】:2016-01-10 20:38:54
【问题描述】:

据我了解,元组和字符串是不可变的,可以进行优化,例如重用不会改变的内存。然而,一个明显的优化,使元组切片与原始元组引用相同的内存,并没有包含在 python 中。

我知道这个优化不包括在内,因为当我对以下函数计时时,所花费的时间像 O(n^2) 而不是 O(n),所以会发生完整的复制:

def test(n):
    tup = tuple(range(n))
    for i in xrange(n):
        tup[0:i]

如果实施了这种优化,python 的某些行为会改变吗?即使原始文件是不可变的,复制也会带来一些性能优势吗?

【问题讨论】:

  • 有时答案是“因为还没有人花时间完全实现它”。
  • 提交拉取请求 :)
  • 正如您所指出的,这可能是在减少复制量和减少对原始元组的引用计数之间进行权衡,以便更早地对其进行垃圾收集。
  • 算法复杂性并不是最终的结果;如果创建视图具有(相对)大的固定成本,我不会感到惊讶。

标签: python


【解决方案1】:

view,您是否想到了与numpy 相同的东西?我很熟悉numpy 这样做的方式和原因。

numpyarray 是一个具有形状和 dtype 信息的对象,外加一个数据缓冲区。您可以在 __array_interface__ 属性中查看此信息。 view 是一个新的 numpy 对象,具有自己的 shape 属性,但具有指向源缓冲区中某个位置的新数据缓冲区指针。它还有一个标志,上面写着“我不拥有缓冲区”。 numpy 还维护自己的引用计数,因此如果原始(所有者)数组被删除(并被垃圾回收),数据缓冲区不会被破坏。

这种视图的使用可以节省大量时间,尤其是对于非常大的数组(关于内存错误的问题在 SO 上很常见)。视图也允许不同的dtype,所以一个数据缓冲区可以查看4字节整数,或者1字节字符等。

这将如何应用于元组?我的猜测是它需要很多额外的行李。元组由一组固定的对象指针组成——可能是一个 C 数组。视图将使用相同的数组,但具有自己的开始和结束标记(指针和/或长度)。共享标志呢?垃圾回收?

元组的典型大小和用途是什么?元组的一个常见用途是将参数传递给函数。我的猜测是,典型 Python 运行中的大多数元组都很小 - 0、1 或 2 个元素。切片是允许的,但它们很常见吗?在小元组还是非常大的元组上?

制作元组切片视图(在 numpy 意义上)会有任何意想不到的后果吗?视图和副本之间的区别是numpy 用户较难掌握的事情之一。由于元组应该是不可变的——即元组中的指针不能更改——实现视图可能对用户是不可见的。但我还是想知道。

PyPy 版本的分支上尝试这个想法可能是最有意义的——除非你真的想深入研究Cpython 代码。或者作为带有Cython 的自定义类。

【讨论】:

    猜你喜欢
    • 2011-10-17
    • 2015-08-22
    • 2011-07-05
    • 2013-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多