Python中打印"[...]"表示什么意思?对于一个对象引用而言。

48

我正在打印我以为是列表的值,但我的输出结果是:

[...]

这代表什么?我该如何进行测试?我已经尝试过:

myVar.__repr__() != '[...]'

myVar.__repr_() != Ellipsis

但是没有成功...

以下是导致问题的代码精简版:

def buildPaths(graph, start, end, path=[], totalPaths=[]):
    """
    returns list of all possible paths from start node to the end node
    """
    path = path + [start]
    if start == end:
        return path
    for nextNode in graph.childrenOf(start):
        if nextNode not in path:
            newPath = buildPaths(graph, nextNode, end, path, totalPaths)
            if newPath != []: # test
                totalPaths.append(newPath)
    return totalPaths

totalPaths 包含很多看起来像是递归列表的内容,但我不清楚为什么。我已经在 #test 中修改了测试以防止这种情况发生。

我还尝试过:

def buildPaths(graph, thisNode, end, path=[], totalPaths=None):
    """
   returns list of all possible paths from start node to the end node
   """
    path = path + [thisNode]
    if thisNode == end:
        return path
    for nextNode in graph.childrenOf(thisNode):
        if nextNode not in path:
            newPath = buildPaths(graph, nextNode, end, path, totalPaths)
            if newPath != None:
                if totalPaths == None:
                    totalPaths = [newPath]
                else:
                    totalPaths.append(newPath)
    return totalPaths
为了明确地返回空路径的None

1
虽然在Python中有Ellipsis这个东西,但它可能只是显示告诉你要显示的内容比可以显示的还多。 >>> [...] -> [Ellipsis] (自Python3起)。 - anthony sottile
2
你能提供一个生成这个的代码示例吗? - BrenBarn
@BrenBarn - 示例代码已添加 - Dycey
1
当你执行totalPaths.append(newPath)时,这会修改传入的列表,因此父递归的totalPaths也会被修改 - 然后作为newPath返回并附加到自身。 - Izkata
谢谢@Izkata - 这就是我想要的解释! - Dycey
4个回答

49

它代表结构内的无限循环。例如:

In [1]: l = [1, 2]

In [2]: l[0] = l

In [3]: l
Out[3]: [[...], 2]

l 的第一个元素是它自己。这是一个递归引用,因此 Python 无法合理地显示其内容。相反,它显示为 [...]


如果它被惰性计算,那么它可以显示结果。 GHCi 显示无限列表没有问题。 - Carcigenicate
22
就实际操作而言,GHCi 在开始显示无限列表时并没有问题,但在结束时会遇到困难...... Python 运行时需要执行完 repr 才能打印输出。 - matsjoyce
1
Common Lisp有一种特殊的表示法来打印“循环”列表结构,请参见https://dev59.com/MWQn5IYBdhLWcg3wpYf0。 - zwol

31

根据上下文,这可能指不同的事情:

使用 Ellipsis 进行索引/切片

我认为它对于任何 Python 类都没有实现,但它应该表示任意数量的数据结构嵌套(取决于需要的深度)。 例如:a[..., 1] 应返回最内层嵌套结构的所有第二个元素:

>>> import numpy as np
>>> a = np.arange(27).reshape(3,3,3)  # 3dimensional array
>>> a[..., 1]  # this returns a slice through the array in the third dimension
array([[ 1,  4,  7],
       [10, 13, 16],
       [19, 22, 25]])
>>> a[0, ...]  # This returns a slice through the first dimension
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])

要检查这个...,您需要将其与Ellipsis进行比较(这是一个单例,建议使用is):

>>> ... is Ellipsis
True
>>> Ellipsis in [...]
True
# Another (more or less) equivalent alternative to the previous line:
>>> any(i is Ellipsis for i in [1, ..., 2]) 
True

递归数据结构

如果你在输出中看到了[...],那么另一种情况是你在序列内部包含了该序列本身。在这种情况下,它表示一个无限深度嵌套的序列(不可打印)。例如:

>>> alist = ['a', 'b', 'c']
>>> alist[0] = alist
>>> alist
[[...], 'b', 'c']

# Infinite deeply nested so you can use as many leading [0] as you want
>>> alist[0][1] 
'b'
>>> alist[0][0][0][0][0][1] 
'b'
>>> alist[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][1] 
'b'

你甚至可以多次替换它:

>>> alist[2] = alist
>>> alist
[[...], 'b', [...]]
>>> alist[1] = alist
>>> alist
[[...], [...], [...]]

如果要测试输出中是否存在这样的递归,您需要检查数据结构本身是否也是其中一个元素:

>>> alist in alist
True
>>> any(i is alist for i in alist)
True

另一种获得更有意义输出的方式是使用 pprint.pprint

>>> import pprint
>>> pprint.pprint(alist)  # Assuming you only replaced the first element:
[<Recursion on list with id=1628861250120>, 'b', 'c']

21
如果您的列表包含自引用,Python会将其显示为[...],而不是尝试递归打印它,这将导致无限循环:
>>> l = [1, 2, 3]
>>> print(l)
[1, 2, 3]
>>> l.append(l)
>>> print(l)
[1, 2, 3, [...]]
>>> print(l[-1])        # print the last item of list l
[1, 2, 3, [...]]
>>> print(l[-1][-1])    # print the last item of the last item of list l
[1, 2, 3, [...]]

无限地。

词典也会出现类似的情况:

>>> d = {}
>>> d['key'] = d
>>> print(d)
{'key': {...}}
>>> d['key']
{'key': {...}}
>>> d['key']['key']
{'key': {...}}

11

由于列表包含自身,因此它是一个递归引用。Python不会尝试递归地打印它,否则会导致无限循环。

repr会检测到这一点。因此,如果您查看列表对象的内部表示,您会看到(省略号所在位置)“引用相同地址上的同一列表对象*”,其中*是原始列表对象在内存中的地址。因此,出现了无限循环。


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