Запутать [...] Список в Python: что это такое?
Итак, я написал простое двоичное дерево в Python и наткнулся на [...]
Я не считаю, что это связано с объектом Ellipsis, но похоже, что он имеет какое-то отношение к бесконечному циклу (из-за мелкой копии Python?). Источником этого цикла бесконечности и почему он не расширяется при расширении при доступе, является то, что я полностью потерял, однако
>>> 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
Так что же такое [...]?
Ответы
Ответ 1
Он также может появиться, если у вас есть круговая структура с списком, указывающим на себя. Вот так:
>>> a = [1,2]
>>> a.append(a)
>>> a
[1, 2, [...]]
>>>
Поскольку python не может распечатать структуру (это был бы бесконечный цикл), он использует многоточие, чтобы показать, что в структуре существует рекурсия.
Я не совсем уверен, был ли вопрос в том, что происходит или как его исправить, но я попытаюсь исправить перечисленные выше функции.
В обоих случаях вы сначала делаете два рекурсивных вызова, которые добавляют данные в список y
, а затем AGAIN присоединяют возвращаемые данные к 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
(Конечно, оба этих фрагмента требуют обработки для пустых списков и т.д.)
@Abgan также отметил, что вы действительно не хотите y=[]
в инициализаторе.
Ответ 2
Я считаю, что ваше "дерево" содержит себя, поэтому оно содержит циклы.
Попробуйте этот код:
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 для более подробной информации об изменяемых объектах, переданных как значения по умолчанию для функций.
Ответ 3
Я не понимаю ваш код выше, но [...] Я думаю, что интерпретатор Python пропускает бесконечные структуры данных. Например:
>>> a = [0, 1]
>>> a[0] = a
>>> a
[[...], 1]
Похоже, ваша древовидная структура становится зацикленной.
Ответы на объекты среза находятся рядом с точкой.
Ответ 4
Я не считаю, что это связано с объектом 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 останавливается на первом этапе рекурсии и имеет дело с проблемой бесконечности, печатающей только многоточие, как было указано в предыдущих ответах.
Ответ 5
Если бы вы использовали 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]()
Ответ 6
EDIT: Как упоминалось выше, это не объект Ellipsis, а результат зацикленного списка. Я прыгнул сюда. Знание об объекте Ellipsis - это хороший бит знаний о полке, если вы найдете Ellipsis в некотором фактическом коде, а не на выходе.
Объект Ellipsis в Python используется для расширенной нотации фрагментов. Он не используется в текущих базовых библиотеках Python, но доступен разработчикам для определения в их собственных библиотеках. Например, NumPy (или SciPy) используют это как часть своего объекта массива. Вам нужно будет посмотреть документацию для tree(), чтобы точно знать, как работает Ellipsis в этом объекте.
От Документация по Python:
3.11.8 Объект с эллипсисом
Этот объект используется расширенным срезом обозначение (см. ссылку на Python Руководство). Он не поддерживает никаких специальных операции. Существует ровно один объект с эллипсисом, названный Ellipsis (a встроенное имя).
Это написано как Эллипсис.
Ответ 7
Хорошо, поэтому в точках:
-
Вы создаете бесконечные данные
Структура:
def Keys(x,y=[])
будет использовать один и тот же "y" в
каждый звонок. Это неверно.
-
Оператор print
, однако, достаточно умен, чтобы не печатать бесконечные данные, а для отметки саморекламы с помощью [...] (известного как Ellipsis)
- Python позволит вам правильно адресовать такую структуру, поэтому вы можете написать
a.keys()[1][1][1]
и так далее. Почему вы не должны?
- Оператор
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 []
Ответ 8
Для разницы между двумя версиями функции Keys обратите внимание на следующую разницу:
y+=[x[2]]+Keys(x[0],y)+Keys(x[1],y)
Правое значение в этом выражении представляет собой список, содержащий x [2], плюс ЭЛЕМЕНТЫ Ключей (x [0], y) и ЭЛЕМЕНТЫ КЛЮЧЕЙ (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 будет содержать свои элементы.
Некоторые другие примечания:
-
Так как в python объект значения по умолчанию создается один раз, когда функция определена, первая версия не будет работать, как показывает пример. Он будет содержать несколько копий некоторых ключей. Трудно объяснить кратко, но вы можете получить некоторое представление, напечатав значения x, y при каждом вызове ключей.
Это подтверждается запуском функции на моей машине с помощью python 2.5.2.
-
Кроме того, поскольку значение по умолчанию определяется только один раз во время определения функции, даже функция работает правильно в первый раз, она не будет работать при вызове с другим а, поскольку ключи в первом двоичном дереве будут остаются в y.
Вы можете увидеть это, дважды нажав клавиши (a) или называя его в двух разных списках.
-
Второй параметр не требуется для этой проблемы. Функция может быть такой:
def Клавиши (a): если a = []: вернуть [] еще: return [a [2]] + Ключи (a [0]) + Ключи (a [1])
Определение рекурсивной функции в основном содержит две части, разрешает подзадачи и объединяет результаты. В вашем коде комбинированная часть результатов повторяется дважды: одна путем их накопления в y, одна - путем добавления списка вместе.
Ответ 9
Проблема заключается в том, что один из элементов списка ссылается на сам список. Поэтому, если попытка распечатать все элементы будет выполнена, это никогда не закончится.
Иллюстрация:
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]
.
Это можно визуализировать лучше
[здесь] (http://pythontutor.com/visualize.html#code=x+%3D+range(3%29%0Ax.append(x%29%0Ax%5B3%5D%5B3%5D%5B3%5D%5B3%5D%5B3%5D%5B0%5D+%3D+5%0Aprint+x&mode=display&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=2&rawInputLstJSON=%5B%5D&curInstr=4)