在闲逛命名空间时,我注意到一个名为 Ellipsis
的奇怪对象,它似乎并没有做任何特别的事情,但它是一个全局可用的内置函数。
经过搜索,我发现它被 Numpy 和 Scipy 用于切片语法的一些晦涩变体中......但几乎没有别的。
是否将此对象添加到语言中专门用于支持 Numpy + Scipy?省略号有任何通用含义或用途吗?
D:\workspace\numpy>python
Python 2.4.4 (#71, Oct 18 2006, 08:34:43) [MSC v.1310 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> Ellipsis
Ellipsis
x=[];x.append(x);print(x)
,看看它如何处理字符串化循环对象。它返回 [[...]]
。我想“我想知道如果我输入 [[...]]
会发生什么?我猜它会抛出一个语法错误。相反,它返回 [[Ellipsis]]
。Python 太奇怪了。随后的谷歌搜索把我带到了这个页面。
...
只是一个占位符,与 Ellipsis
无关
这在最近的另一个 question 中出现。我将从那里详细说明我的 answer:
Ellipsis 是一个可以以切片表示法出现的对象。例如:
myList[1:2, ..., 0]
它的解释完全取决于实现 __getitem__
函数并在那里看到 Ellipsis
对象的任何东西,但它的主要(和预期)用途是在 numpy 第三方库中,它添加了一个多维数组类型。由于有多个维度,切片变得比仅仅一个开始和停止索引更复杂;能够在多个维度上切片也很有用。例如,给定一个 4 × 4 数组,左上角区域将由切片 [:2, :2]
定义:
>>> a
array([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12],
[13, 14, 15, 16]])
>>> a[:2, :2] # top left
array([[1, 2],
[5, 6]])
进一步扩展这一点,省略号在这里用于指示未指定的其余数组维度的占位符。将其视为在其放置的间隙中指示所有维度的完整切片 [:]
,因此对于 3d 数组,a[..., 0]
与 a[:, :, 0]
相同,对于 4d a[:, :, :, 0]
,类似地,a[0, ..., 0]
是 a[0, :, :, 0]
(中间有许多冒号构成了数组中的全部维数)。
有趣的是,在 python3 中,省略号文字 (...
) 可以在切片语法之外使用,因此您实际上可以编写:
>>> ...
Ellipsis
编辑:省略号也用于标准库 typing
模块:例如 Callable[..., int]
表示返回 int
而不指定签名的可调用对象,或 tuple[str, ...]
表示字符串的可变长度同质元组。
在 Python 3 中,您可以¹使用省略号文字 ...
作为尚未编写的代码的“nop”占位符:
def will_do_something():
...
这不是魔法;可以使用任何表达式代替 ...
,例如:
def will_do_something():
1
(不能使用“sanctioned”这个词,但我可以说这个用法是 Guido 的not outrightly rejected。)
¹ 'can' not in {'must', 'should'}
...
用于人们想要表示他们打算稍后填写的内容(“待办事项”空块),而 pass
表示打算没有代码的块。
NotImplemented
文字,当您希望不完整的函数返回有意义的内容时(而不是示例中的 None
),这很有用。 (另一个用例:Implementing arithmetic operations)
NotImplemented = 'something_else'
是有效的 Python,但 ... = 'something_else'
是语法错误。
总结其他人所说的,从 Python 3 开始,Ellipsis 本质上是另一个类似于 None
的单例常量,但没有特定的预期用途。现有用途包括:
在切片语法中表示剩余维度中的完整切片
在类型提示中仅指示类型的一部分(Callable[..., int] 或 Tuple[str, ...])
在类型存根文件中表示有一个默认值而不指定它
可能的用途可能包括:
作为 None 是有效选项的地方的默认值
作为您尚未实现的功能的内容
...
作为默认值。 None
至少传达了“没有传递值”的语义; ...
没有。备用标记通常是 object
或自定义类的特制实例,旨在使用 is
进行测试。例如,参见 dataclasses
module,它以这种方式定义了几个自定义标记。
Ellipsis
与 None
不同。
None
值的函数中使用 ...
作为参数的默认值(表示没有真正传递给该参数)。 def function(param1 = 5, param2 = ...): if not param2 is Ellipsis: #do something else: #do something else
- 例如,此函数可能与传入的 None
值有关。因此我们在这里使用 ...
或 Ellipsis
作为默认值,这是合理的,因为该对象没有实际用途(至少不适合我)
您还可以在指定预期的 doctest 输出时使用省略号:
class MyClass(object):
"""Example of a doctest Ellipsis
>>> thing = MyClass()
>>> # Match <class '__main__.MyClass'> and <class '%(module).MyClass'>
>>> type(thing) # doctest:+ELLIPSIS
<class '....MyClass'>
"""
pass
...
的大多数(如果不是全部)使用都是句法,而不是 use
实际的 Ellipsis 对象。它真的只是一个适应性概念的方便名称吗?
...
。
此对象通常由切片使用(请参阅切片)。它不支持特殊操作。只有一个省略号对象,名为 Ellipsis(内置名称)。 type(Ellipsis)() 生成 Ellipsis 单例。它被写为省略号或....
__getitem__
自定义类中的最小 ...
示例
在自定义类中将魔术语法 ...
传递给 []
时,__getitem__()
会收到一个 Ellipsis
类对象。
然后该类可以对这个 Singleton 对象做任何它想做的事情。
例子:
class C(object):
def __getitem__(self, k):
return k
# Single argument is passed directly.
assert C()[0] == 0
# Multiple indices generate a tuple.
assert C()[0, 1] == (0, 1)
# Slice notation generates a slice object.
assert C()[1:2:3] == slice(1, 2, 3)
# Ellipsis notation generates the Ellipsis class object.
# Ellipsis is a singleton, so we can compare with `is`.
assert C()[...] is Ellipsis
# Everything mixed up.
assert C()[1, 2:3:4, ..., 6] == (1, slice(2,3,4), Ellipsis, 6)
Python 内置的 list
类选择赋予它范围的语义,当然,任何合理的用法也应该如此。
就个人而言,我只是在我的 API 中远离它,而是创建一个单独的、更明确的方法。
在 Python 3.5.2 和 2.7.12 中测试。
对于在大量使用 Pydantic 的代码库中工作而获得此答案的任何人:这也是 Pydantic 指示一个必需但可以设置为 None
的字段的方式,他们将其称为“required optional fields”。这也是为什么它们最终也被用于 FastAPI 的原因。
您可以自己使用 Ellipsis,在像 numpy 这样的自定义切片情况下,但它在任何内置类中都没有使用。
我不知道它是否是专门为在 numpy 中使用而添加的,但我当然没有看到它在其他地方使用过。
另请参阅:How do you use the ellipsis slicing syntax in Python?
正如@noɥʇʎԀʎzɐɹƆ 和 @phoenix 所提到的 - 您确实可以在存根文件中使用它。例如
class Foo:
bar: Any = ...
def __init__(self, name: str=...) -> None: ...
可以在此处找到有关如何使用此省略号的更多信息和示例https://www.python.org/dev/peps/pep-0484/#stub-files
None
。
module.pyi
存在用于静态类型检查,它不是可执行代码。它用于向没有它的模块添加类型信息。在这种用法def foo(bar:str=...)->str
中,它表示有一个默认值(即参数是可选的),但没有指明默认值是什么。
bar: Any = ...
和 -> None: ...
是什么?哦,我认为 -> None:
之后的 ...
可能只是表示方法的主体?
bar: Any = ...
表示 Foo
有一个类型为 Any
的名为 bar
的成员,具有未指定的默认值。 pyi 文件通常会这样做。
它的预期用途不应仅用于这些第 3 方模块。 Python 文档中没有正确提及它(或者我可能只是找不到),但 省略号 ...
实际上在 CPython 中至少在一个地方使用过。
它用于表示 Python 中的无限数据结构。我在玩列表时遇到了这个符号。
有关详细信息,请参阅 this question。
ellipsis
内置类型和 Ellipsis
对象。用省略号表示无限数据结构纯粹是为了显示,与 ellipsis
类型或 Ellipsis
对象无关。
__repr__
字符串旨在成为有效的 Python 表达式 - 如果它不是语言中存在的省略号,那么表示将不是有效的表达式。
eval(repr(a))
目标等于 a
。不幸的是,在实践中它有时是错误的,即使对于内置类型也是如此。试试这个:a=[]; a.append(a); eval(repr(a))
。 repr(a)
是 [[...]]
,在 Python 2 中是无效的表达式。(在 Python 3 中它是有效的,但是 eval 的结果有些不同,仍然违背了初衷。)
这是等价的。
l=[..., 1,2,3]
l=[Ellipsis, 1,2,3]
...
是在 built-in constants
中定义的常量。
省略号 与省略号文字“...”相同。特殊值主要与用户定义的容器数据类型的扩展切片语法结合使用。
在 typer 中,...
用于创建必需的参数:Argument
类需要一个默认值,如果您传递 ...
,如果用户未传递特定参数,它会报错。
如果 Ellipsis
不存在,您可以使用 None
,但这将失去表达 None
是默认值的机会,以防在您的程序中有任何意义.
typing
模块中:例如Callable[..., int]
表示返回int
而不指定签名的可调用对象,或Tuple[str, ...]
表示可变长度同质元组的字符串。a = [1, 2]; a[0] = a; print(a)
给出[[...], 2]
。这是同一件事还是不同的用途?