如何在Python中使用省略号切片语法?

210

这个问题在Python 隐藏特性中出现,但我找不到好的文档或示例来解释该功能的工作原理。

4个回答

307

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

它的设计是表示在此处插入尽可能多的完整切片(:)以将多维切片扩展到所有维度

例子

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

现在,你有一个二阶二次方的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])

在你自己的实现中,你可以自由地忽略上述提到的契约并将其用于任何你认为合适的用途。


1
也许我错了,但是a[:,:,:,0]不是会返回一个复制品,而a[...,0]会返回“视图”而非复制品吗? 我试着对这两种版本分别运行id(),对于一个三维数组:a[:,:,:, 1], a[:,:,:, 2]它们的ID都不同,而:a[..., 1], a[..., 2]它们的ID都相同。 - mohitsharma44
1
@mohitsharma44 不在我的电脑上 ;) id() 返回相同的值。同时,使用 __array_interface__['data'] 进行检查显示相同的内存地址。 - BoltzmannBrain
1
我发现即使a是一维数组,我们仍然可以使用a[indexes, ...] - acgtyrant
4
4维矩阵是什么?将其称为4维数组有意义,但不应该称其为矩阵,我个人的看法。 - kmario23
5
省略号对于零维数据结构也很有用。它们是我所知道的唯一一种可以写入标量numpy.ndarrays的方法,例如:my_scalar = np.asarray(3); my_scalar[...] = 5。如果您执行my_scalar[:] = 5,您会 rightly 收到一个错误,因为没有0维可供:迭代。 - SuperElectric
3
@SuperElectric 你也可以使用 my_scalar.itemset(scalarvalue)。当然,my_scalar[...]=scalar_value 更短,但你在上面的评论中说,这是你知道的唯一方法。只是提供一个替代方案。 - kamathln

133
Ellipsis, 或者...不是一个隐藏的功能,它只是一个常量。这与JavaScript ES6很不相同,后者是语言语法的一部分。没有任何内置类或Python语言构造使用它。
因此,它的语法完全取决于你或其他人编写的代码是否理解它。
Numpy使用它,正如文档中所述。一些例子在此处
在您自己的类中,您可以像这样使用它:
>>> 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文档语言参考。但那些并没有什么用。


8
看起来很破损。因为"适当"的说法是:
x[:] x[:, 1:2]
- user78110
37
@Ronny: 这个例子的重点是展示一些自定义使用省略号的方法。 - nosklo
9
链接似乎已经失效。 - SwiftsNamesake

74

这是省略号的另一个用法,与切片无关:我经常在线程内部与队列通信时使用它作为表示“完成”的标记;它就在那里,是一个对象,是一个单例,其名称意味着“缺乏”,并且它不是过度使用的 None(可以作为正常数据流的一部分放入队列中)。个人经验可能有所不同。


15
直接说“Done = object()”会更清晰明了,你可以在某处这样写,并直接使用它。 - Brandon Rhodes
13
不一定需要-它要求你实际上在某个地方“说”Done=object()。 哨兵值不一定是坏事-并且使用原本几乎毫无用处的Python单例作为哨兵并不那么可怕(在我看来,省略号和()是我使用的其中两个,在这些情况下使用None会让人感到困惑)。 - Rick Copeland
7
关于 Done = object(),我认为使用省略号更好,尤其是在与队列通信时。如果您从线程内通信转换到进程内通信,则在另一个进程中 id(Done) 将不同,并且没有什么可以区分一个对象与另一个对象。省略号的 id 也将不同,但至少类型相同 - 这是单例的关键之处。 - Tristan Reid
问题说的是“如何使用省略号”,但我认为你理解错了。它有许多解释。但我认为正确的解释是:“省略号怎么用?”,即“我应该采取哪些步骤,在自己的代码中使用省略号。” - Frames Catherine White

15

正如其他答案所述,它可以用于创建切片。当您不想编写许多完整的切片符号(:)时非常有用,或者当您不确定正在操作的数组的维数时。

我认为需要强调的重要点是,即使没有更多的维度需要填充,它也可以使用。

例如:

>>> 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])

"这会起作用,当然,但我们对它起作用的原因感兴趣。也许是因为Numpy将...解释为“添加正确数量的,以便根据数组形状创建有效的索引”。在您的示例中,它不添加任何内容,对于3D数组,它将添加:,,对于4D数组,它将添加:,:,等等。这种解释是Numpy的解释,但另一个软件包或另一个开发者可能会以完全不同的方式解释...,只要他们解释如何使用它。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接