Запутанный список [...] в Python: что это? - PullRequest
17 голосов
/ 29 декабря 2008

Итак, я писал простое двоичное дерево на Python и наткнулся на [...]

Я не верю, что это связано с объектом Ellipsis, более похоже, что он как-то связан с бесконечным циклом (из-за мелкой копии Python?). Однако источник этого бесконечного цикла и почему он не расширяется при расширении при доступе - это то, к чему я полностью потерян </p> <pre><code>>>> a [[[[[], [], 8, 3], [[], [], 3, 2], 6, 3], [], 1, 4], [[], [], -4, 2], 0, 0] >>> Keys(a)#With a+b [0, 1, 6, 8, 3, -4] >>> Keys(a)#With [a,b] [8, [...], [...], 3, [...], [...], 6, [...], [...], 1, [...], [...], -4, [...], [...], 0, [...], [...]] >>> Keys(a)[1]#?? [8, [...], [...], 3, [...], [...], 6, [...], [...], 1, [...], [...], -4, [...], [...], 0, [...], [...], 8, [...], [...], 3, [...], [...], 6, [...], [...], 1, [...], [...], -4, [...], [...], 0, [...], [...]]

Версия с использованием + b

def Keys(x,y=[]):
    if len(x):y+=[x[2]]+Keys(x[0],y)+Keys(x[1],y)#Though it seems I was using y=y[:]+, this actually outputs an ugly mess
    return y

версия с использованием [a, b]

def Keys(x,y=[]):
    if len(x):y+=[x[2],Keys(x[0],y),Keys(x[1],y)]
    return y

Так что же такое [...]?

Ответы [ 9 ]

25 голосов
/ 29 декабря 2008

Может также появиться, если у вас круговая структура со списком, указывающим на себя. Как это:

>>> a = [1,2]
>>> a.append(a)
>>> a
[1, 2, [...]]
>>> 

Поскольку python не может распечатать структуру (это был бы бесконечный цикл), он использует многоточие, чтобы показать, что в структуре есть рекурсия.


Я не совсем уверен, был ли вопрос в том, что происходит или как это исправить, но я постараюсь исправить указанные выше функции.

В обоих из них вы сначала делаете два рекурсивных вызова, которые добавляют данные в список y, а затем СНОВА добавляют возвращаемые данные к y. Это означает, что одни и те же данные будут присутствовать несколько раз в результате.

Либо просто соберите все данные, не добавляя ни к одному y, с чем-то вроде

return [x[2]]+keys(x[0])+keys(x[1])

или просто добавьте в вызовы что-то вроде

y += [x[2]]
keys(x[0], y) #Add left children to y...
keys(x[1], y) #Add right children to y...
return y

(Конечно, оба этих фрагмента требуют обработки для пустых списков и т. Д.)

@ Абган также заметил, что вы действительно не хотите y=[] в инициализаторе.

6 голосов
/ 29 декабря 2008

Я считаю, что ваше «дерево» содержит себя, поэтому оно содержит циклы.

Попробуйте этот код:

   a = [1,2,3,4]
   print a
   a.append(a)
   print a

Первые выходные данные печати:

  [1,2,3,4]

пока второе:

  [1,2,3,4, [...]]
 

причина использования

 def Keys(x,y=[]):
 
Это неправильно и зло. Список является изменяемым объектом, и при использовании в качестве параметра по умолчанию он сохраняется между вызовами функций. Таким образом, каждая операция y + = "что-нибудь" добавляет к одному и тому же списку (во всех вызовах функций, и поскольку функция является рекурсивной ...)

См. Effbot или Devshed для получения дополнительной информации об изменяемых объектах, передаваемых в качестве значений по умолчанию для функций.

5 голосов
/ 29 декабря 2008

Я не понимаю ваш код выше, но [...] я думаю, что интерпретатор Python пропускает бесконечные структуры данных. Например:

>>> a = [0, 1]
>>> a[0] = a
>>> a
[[...], 1]

Похоже, ваша древовидная структура становится зацикленной.

Ответы об объектах среза не имеют отношения к делу.

4 голосов
/ 10 марта 2013

Если бы вы использовали PrettyPrinter, вывод был бы очевиден

>>> l = [1,2,3,4]
>>> l[0]=l
>>> l
[[...], 2, 3, 4]
>>> pp = pprint.PrettyPrinter(indent = 4)
>>> pp.pprint(l)
[<Recursion on list with id=70327632>, 2, 3, 4]
>>> id(l)
70327632

Другими словами это что-то вроде

enter image description here

4 голосов
/ 29 декабря 2008

Я не верю, что это связано с объектом Ellipsis, больше похоже, что он имеет отношение к бесконечному циклу (из-за мелкой копии Python?). Источник этого бесконечного цикла и почему он не расширяется при расширении при доступе - это то, к чему я полностью потерян, однако

Посмотрите на следующий код:

>>> a = [0]
>>> a.append(a)
>>> print a
[0, [...]]

Как Python должен печатать? Это список, который содержит ноль и ссылку на себя. Следовательно, это список, который содержит ноль и ссылку на список

[0, [...]]

который в свою очередь содержит ноль и ссылку на список

[0, [0, [...]]]

который в свою очередь содержит ноль и ссылку на список, и так далее, рекурсивно:

[0, [0, [0, [...]]]]
[0, [0, [0, [0, [...]]]]]
[0, [0, [0, [0, [0, [...]]]]]]
...

В самой рекурсивной структуре данных нет ничего плохого. Единственная проблема заключается в том, что не может быть отображено , поскольку это будет означать бесконечную рекурсию. Следовательно, Python останавливается на первом шаге рекурсии и решает проблему бесконечности, печатая только многоточие, как было указано в предыдущих ответах.

2 голосов
/ 29 декабря 2008

EDIT: как уже упоминалось выше, это не объект Ellipsis, а результат зацикленного списка. Я бросил пистолет здесь. Знание об объекте Ellipsis - это хорошая основа знаний, если вы найдете Ellipsis в каком-то реальном коде, а не в выводе.


Объект Ellipsis в Python используется для расширенной записи слайса. Он не используется в текущих базовых библиотеках Python, но доступен для разработчиков для определения в своих собственных библиотеках. Например, NumPy (или SciPy) используют это как часть своего объекта массива. Вам нужно будет просмотреть документацию для tree (), чтобы точно знать, как Ellipsis ведет себя в этом объекте.

С Документация Python :

3.11.8 Объект эллипса

Этот объект используется расширенным срезом обозначение (см. Python Reference Руководство). Не поддерживает никаких специальных операции. Есть ровно один объект с многоточием, названный Ellipsis ( встроенное имя).

Это написано как многоточие.

1 голос
/ 23 июля 2016

Проблема в том, что один из элементов списка ссылается на сам список. Таким образом, если попытаться напечатать все элементы, то это никогда не закончится.

Иллюстрация:

x = range(3)
x.append(x)
x[3][3][3][3][3][0] = 5
print x

Выход:

[5, 1, 2, [...]]

x[3] относится к самому x. То же самое касается x[3][3].

Это можно визуализировать лучше здесь

1 голос
/ 29 декабря 2008

Для различия между двумя версиями функциональных клавиш обратите внимание на следующее различие:

y+=[x[2]]+Keys(x[0],y)+Keys(x[1],y)

Правое значение в этом утверждении - это список, который содержит x [2], плюс ELEMENTS OF Keys (x [0], y) и ELEMENTS OF Keys (x [1], y)

y+=[x[2],Keys(x[0],y),Keys(x[1],y)]

Правое значение в этом выражении - это список, который содержит x [2], плюс ключи LIST (x [2], y) и ключи LIST (x [1], y).

Таким образом, версия, использующая [a, b], будет вызывать y в качестве своих элементов.

Некоторые другие заметки:

  1. Поскольку в python объект значения по умолчанию создается один раз при определении функции, первая версия не будет работать, как показано в примере. Он будет содержать несколько копий некоторых ключей. Это сложно объяснить вкратце, но вы можете получить некоторую идею, напечатав значения x, y при каждом вызове ключей.

    Это подтверждается запуском функции на моей машине с python 2.5.2.

  2. Кроме того, поскольку значение по умолчанию определяется только один раз во время определения функции, даже функция работает правильно в первый раз, она не будет работать при вызове с другим a, поскольку ключи в первом двоичном дереве будут оставайся у тебя.

    Это можно увидеть, дважды вызвав Keys (a) или вызвав его из двух разных списков.

  3. Второй параметр не требуется для этой проблемы. Функция может быть такой:

    def Keys (a): если а = []: вернуть [] еще: return [a [2]] + Keys (a [0]) + Keys (a [1])

    Определение рекурсивной функции в основном состоит из двух частей, решения подзадач и объединения результатов. В вашем коде часть результатов объединения повторяется дважды: один путем их накопления в y, другой - путем сложения списка вместе.

1 голос
/ 29 декабря 2008

Хорошо, так в пунктах:

  1. Вы создаете бесконечные данные структура:

    def Keys(x,y=[])
    будет использовать тот же 'у' в каждый звонок. Это просто не правильно.
  2. Оператор print, однако, достаточно умен, чтобы не печатать бесконечные данные, а чтобы пометить собственную ссылку [...] (известную как Ellipsis )

  3. Python позволит вам правильно обращаться к такой структуре, поэтому вы можете написать
    a.keys()[1][1][1]
    и так далее. Почему ты не должен?
  4. Оператор y = y[:] просто копирует список y. Можно сделать более разумно с y = list(y)

Попробуйте использовать следующий код:

def Keys(x,y=None):
    if y is None:
        y = []
    if len(x):
        y += [x[2], Keys(x[0],y), Keys(x[1],y)]
    return y

Но, тем не менее, я думаю, что это может укусить вас. Вы по-прежнему используете одну и ту же переменную y (я имею в виду тот же объект) в трех местах в одном выражении:

 y += [x[2], Keys(x[0], y), Keys(x[1], y)] 

Это то, чего вы действительно хотите достичь? Или, может быть, вы должны попробовать:

def mKeys(x,y=None):
    if y is None:
        y = []
    if len(x):
       z = [x[2], mKeys(x[0], y), mKeys(x[1],y)]
       return z
   return []
...