Python Ellipsis

这几天在阅读一段源代码时,突然看到了这样的写法:

1
2
class A:
host: Text = ...

当时一愣——这三个点是个什么玩意儿,好像只在 numpy 中切片时用过,怎么突然出现在这里?嗯,于是就有了这篇小文,记录下这个有意思的玩意儿。总的来说,主要有以下几种用法:

  • Numpy Slice:表示「其他维度的所有值」
  • 类型提示:表示「不指定、可变的、任意的」参数类型
  • 占位符:表示类或方法还没写的 Body
  • 循环引用:表示一个循环引用,而不是满屏幕打印
  • 特殊标记:表示一个特殊的位置,比如结束、开始等

首先,这三个点有个学名,叫「Ellipsis」,我们在 Python 中简单执行下:

1
2
3
4
...
# Ellipsis
type(...) # == type(Ellipsis)
# ellipsis

... 在 Python 中就等价于 Ellipsis,类型是 ellipsis。根据在 CPython 源码中的定义,可知它是一个单例:

1
2
3
4
5
6
7
class Ellipsis(Constant, metaclass=_ABC):
_fields = ()

def __new__(cls, *args, **kwargs):
if cls is Ellipsis:
return Constant(..., *args, **kwargs)
return Constant.__new__(cls, *args, **kwargs)

接下来就看它常用在哪些地方。

Numpy切片

这个应该是比较熟悉的了,在索引时,... 往往表示「其他所有维度的值」。先随机生成一个多维矩阵:

1
2
3
4
5
import numpy as np
rng = np.random.default_rng(seed=42)

rng = np.random.default_rng(seed=42)
arr = rng.integers(0, 10, (3, 3, 3))

然后进行切片:

1
2
3
arr[...] == arr
arr[0, ...] == arr[0,:,:]
arr[0, ..., 0] == arr[0,:,0]

使用起来非常方便简洁。

类型提示

类型提示是 Python3.5 开始有的新功能,借鉴自静态语言,主要是对函数或类的参数和返回值类型进行标记,便于代码阅读。... 在其中主要表达「可变或动态提示」,下面用一个例子来说明。

1
2
3
4
5
6
7
8
9
10
11
def demo(
func1: Callable[[int], int],
func2: Callable[..., str],
*args: Tuple[int, ...],
id: ...,
name: str = ...,
addr: str = None,
) -> ...:
print(args, id, name, addr)

# demo(func, func, 2, "3", 4.2, id=1, name="hello")

Callable 提示中第一个表示输入的参数类型,第二个是返回值的类型。

  • 如果 Callable 「参数提示」使用 ...,则表示不指定输入的参数类型
  • 如果「参数类型」使用 [type, ...],则表示参数是变长的,这个经常会用在 Tuple
  • 如果「参数或返回值的类型提示」使用 ...,则表示该参数或返回值是任意类型的,与 Any 等价
  • 如果「参数的默认值」使用 ...,则表示该参数默认值为 Ellipsis,当想区分不传入值或传入 None 时比较有用

占位符

pass 一样的功能,当我们在不关心实现细节,快速搭建代码框架时经常会用到:

1
2
3
4
5
def run():
pass

def test():
...

循环引用

当创建一个循环引用时,Python 会使用 ... 显示无限循环,注意,这并不是真的替换了引用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
a = [0, 1]
a[0] = a

a == a[0] == a[0][0] == a[0][0][0] # True

x = a[0]
for i in range(5):
print(x)
x = x[0]
"""
[[...], 1]
[[...], 1]
[[...], 1]
[[...], 1]
[[...], 1]
"""

特殊标记

有时候会用来当做队列结束的标记,比如:

1
q = [1, 2, 3, ...]

这很容易理解,因为我们既不需要新建一个对象专门作为标记,... 又足够特殊,一般队列的值不会是它。

参考资料