【问题标题】:How do you use the ellipsis slicing syntax in Python?如何在 Python 中使用省略号切片语法?
【发布时间】:2010-09-12 05:08:15
【问题描述】:

这出现在 Hidden features of Python 中,但我看不到很好的文档或示例来解释该功能的工作原理。

【问题讨论】:

    标签: python numpy subclass slice ellipsis


    【解决方案1】:

    省略号在 numpy 中用于对高维数据结构进行切片。

    它的设计意思是此时,插入尽可能多的完整切片 (:) 以将多维切片扩展到所有维度

    示例

    >>> from numpy import arange
    >>> a = arange(16).reshape(2,2,2,2)
    

    现在,您有一个 2x2x2x2 阶的 4 维矩阵。要选择第 4 维中的所有第一个元素,可以使用省略号表示法

    >>> a[..., 0].flatten()
    array([ 0,  2,  4,  6,  8, 10, 12, 14])
    

    相当于

    >>> a[:,:,:,0].flatten()
    array([ 0,  2,  4,  6,  8, 10, 12, 14])
    

    在您自己的实现中,您可以随意忽略上面提到的合同,并将其用于您认为合适的任何事情。

    【讨论】:

    • 也许我错了,但不是a[:,:,:,0] 会返回一个副本,a[...,0] 会返回“视图”而不是副本吗?我尝试针对两个版本和 3 维数组运行 id()a[:,:,:, 0], a[:,:,:, 1], a[:,:,:, 2] 都有不同的 id,而:a[..., 0], a[..., 1], a[..., 2] 都有相同的 id。
    • @mohitsharma44 不在我的机器上;)id() 为两者返回相同的值。还检查__array_interface__['data'] 显示相同的内存地址。
    • 什么是 4 维矩阵?将其称为 4 维数组而不是矩阵是有意义的。,IMO。
    • 椭圆对于零维数据结构也很有用。它们是我知道写入标量 numpy.ndarrays 的唯一方法,例如: my_scalar = np.asarray(3); my_scalar[...] = 5。如果你执行 my_scalar[:] = 5,你会得到一个错误,因为 : 没有维度 0 可以迭代。
    • @SuperElectric 你也可以使用 my_scalar.itemset(scalarvalue)。当然, my_scalar[...]=scalar_value 更短,但是您在上面的评论中说,这是您知道的唯一方法。只是提供一个替代方案。
    【解决方案2】:

    Ellipsis... 不是隐藏功能,它只是一个常数。它与作为语言语法一部分的 javascript ES6 完全不同。没有内置类或 Python 语言构造使用它。

    因此,它的语法完全取决于您或其他人是否编写了代码来理解它。

    Numpy 使用它,如 documentation 中所述。一些例子here

    在你自己的类中,你会这样使用它:

    >>> class TestEllipsis(object):
    ...     def __getitem__(self, item):
    ...         if item is Ellipsis:
    ...             return "Returning all items"
    ...         else:
    ...             return "return %r items" % item
    ... 
    >>> x = TestEllipsis()
    >>> print x[2]
    return 2 items
    >>> print x[...]
    Returning all items
    

    当然,还有python documentationlanguage reference。但这些都不是很有帮助。

    【讨论】:

    • 看起来很糟糕,因为“正确”的方式来表示所有项目是 >>> x[:] >>> x[:, 1:2]
    • @Ronny:重点是演示省略号的一些自定义用法。
    • 链接似乎已损坏。
    【解决方案3】:

    这是省略号的另一种用途,它与切片无关:我经常在与队列的线程内通信中使用它,作为表示“完成”的标记;它在那里,它是一个对象,它是一个单例,它的名字的意思是“缺乏”,它不是过度使用的 None (可以作为正常数据流的一部分放入队列中)。 YMMV。

    【讨论】:

    • 在某处说:“Done = object()”然后使用它不是更清楚吗?
    • 不一定——它需要你在某处实际say Done=object()。哨兵值不一定是坏事——使用其他几乎无用的 Python 单例作为哨兵在 IMO 中并不是那么可怕(省略号和 () 是我使用过的那些没有会混淆的地方)。
    • 关于 Done = object(),我认为使用 Ellipsis 更好,尤其是当您使用它与队列进行通信时。如果从线程内转到进程内通信,id(Done) 在另一个进程中不会相同,没有什么可以区分一个对象和另一个对象。 Ellipsis 的 id 也不会相同,但至少类型会相同 - 这是单例的要点。
    • 问题是“你如何使用省略号”,但我相信你采取了错误的方式。它有多种解释。但我认为正确的是:“省略号是如何使用的?”即“我应该采取哪些步骤来在我自己的代码中使用省略号。”。
    【解决方案4】:

    如其他答案所述,它可用于创建切片。 当您不想编写许多完整的切片表示法 (:),或者您只是不确定要操作的数组的维数时,这很有用。

    我认为重要的是要强调,而其他答案中缺少的是,即使没有更多要填充的维度,它也可以使用。

    例子:

    >>> from numpy import arange
    >>> a = arange(4).reshape(2,2)
    

    这会导致错误:

    >>> a[:,0,:]
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    IndexError: too many indices for array
    

    这将起作用:

    a[...,0,:]
    array([0, 1])
    

    【讨论】:

      猜你喜欢
      • 2016-09-12
      • 2015-07-21
      • 2019-06-25
      • 2021-04-16
      • 1970-01-01
      • 1970-01-01
      • 2012-10-25
      相关资源
      最近更新 更多