O que reticências […] significam em uma lista?

196

Eu estava brincando em python. Eu usei o seguinte código no IDLE:

p  = [1, 2]
p[1:1] = [p]
print p

A saída foi:

[1, [...], 2]

O que é isso […]? Curiosamente, agora eu poderia usar isso como uma lista de lista de lista até o infinito, ou seja

p[1][1][1]....

Eu poderia escrever o texto acima contanto que quisesse e ainda funcionasse.

EDITAR:

  • Como é representado na memória?
  • Qual é o seu uso? Exemplos de alguns casos em que é útil seriam úteis.
  • Qualquer link para a documentação oficial seria realmente útil.
Aseem Bansal
fonte
Ainda procurando respostas para o 1º e o 3º elementos da lista da EDIT.
Aseem Bansal
7
Um exemplo mais simples seria p = [1]; p[0] = p.
Arshajii 18/06
6
Eu acho que isso é uma duplicata do que […] (uma elipse) em uma lista significa em Python? , embora a pergunta (e as respostas) sejam melhores nessa questão.
Martin Thoma
1
Dreampie é inteligente `>>> p [1: 1] = [p] >>> p 3: [1, <Recursão na lista com id = 3074777548>, 2] >>>` fornece os detalhes exatos
Rahul Gautam
@RahulGautam Não entendi p 3: [1, <Recursion on list with id=3074777548>, 2]. O que você correu?
Aseem Bansal

Respostas:

112

Isso significa que você criou uma lista infinita aninhada dentro de si mesma, que não pode ser impressa. pcontém o pque contém p... e assim por diante. A [...]notação é uma maneira de informá-lo e informar que ela não pode ser representada! Dê uma olhada na resposta do @ 6502 para ver uma bela imagem mostrando o que está acontecendo.

Agora, sobre os três novos itens após a sua edição:

  • Esta resposta parece cobri-lo
  • O link de Ignacio descreve alguns usos possíveis
  • Este é mais um tópico do design da estrutura de dados do que linguagens de programação, portanto, é improvável que qualquer referência seja encontrada na documentação oficial do Python.
Óscar López
fonte
Então, está tomando memória infinita? Eu sei que isso não pode ser possível. Como é representado e para que serve?
Aseem Bansal
21
@Zel: Os elementos da lista são referências. O segundo elemento é uma referência à própria lista.
Ignacio Vazquez-Abrams
2
O Python o identificou como um loop infinito de referências, por isso decidiu abreviá-lo, não é realmente infinito. E não, não é realmente útil para além de uma experiência de pensamento :)
Óscar López
2
Existem ... alguns usos para estruturas infinitamente recursivas. Mas não muitos.
Ignacio Vazquez-Abrams
@ IgnacioVazquez-Abrams Alguns exemplos seriam úteis.
Aseem Bansal
316

Isto é o que seu código criou

insira a descrição da imagem aqui

É uma lista em que o primeiro e o último elementos estão apontando para dois números (1 e 2) e onde o elemento do meio está apontando para a própria lista.

No Common Lisp, quando a impressão de estruturas circulares está ativada, esse objeto seria impresso como

#1=#(1 #1# 2)

significando que existe um objeto (rotulado com 1 #1=) que é um vetor com três elementos, o segundo sendo o próprio objeto (com referência anterior #1#).

Em Python, você obtém as informações com as quais a estrutura é circular [...].

Nesse caso específico, a descrição não é ambígua (está apontando para trás para uma lista, mas há apenas uma lista, portanto deve ser essa). Em outros casos, pode ser ambíguo ... por exemplo, em

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

a referência anterior pode apontar para a lista externa ou interna. Essas duas estruturas diferentes impressas da mesma maneira podem ser criadas com

x = [1, [2, 3]]
x[1][1:1] = [x[1]]

y = [1, [2, 3]]
y[1][1:1] = [y]

print(x)
print(y)

e eles estariam na memória como

insira a descrição da imagem aqui

6502
fonte
Você pode encontrar o conteúdo [1, [2, [...], 3]]assim: x[1] = [2, [...], 3]e y[1] = [2, 1, [...]], 3]. Isso significa que x consiste em 1 e depois repete 2s, enquanto y consiste em alternar 1s e 2s.
pascalhein
2
@csharpler: é claro que você pode distinguir os dois analisando o conteúdo, mas eles são impressos com a mesma representação. No formato Common Lisp, eles seriam #(1 #1=#(2 #1# 3))para xe #1=#(1 #(2 #1# 3))para y.
6502
5
@BurhanKhalid: Inkscape para o primeiro e GIMP para o segundo (porque eu joguei fora o SVG)
6502
1
@csharpler: você não pode criar uma "lista infinita" em Python porque as listas são de fato redimensionáveis, não listas vinculadas. Uma "lista infinita" no Common Lisp poderia ser criada com #1=(1 . #1#).
6502
1
+ se você quiser desenhar um diagrama de ACSII como este, tente: Asiiflow
Grijesh Chauhan
23

Para a pergunta "Qual é o seu uso", aqui está um exemplo concreto.

A redução de gráfico é uma estratégia de avaliação usada em algum momento para interpretar uma linguagem de computador. Essa é uma estratégia comum para avaliação lenta, principalmente de linguagens funcionais.

O ponto de partida é criar um gráfico representando a sequência de "etapas" que o programa executará. Dependendo das estruturas de controle usadas no programa, isso pode levar a um gráfico cíclico (porque o programa contém algum tipo de loop "para sempre" - ou usa uma recursão cuja "profundidade" será conhecida no momento da avaliação , mas não no gráfico. hora de criação ) ...

Para representar esse gráfico, você precisa de "estruturas de dados" infinitas (às vezes chamadas de estruturas de dados recursivas ), como a que você notou. Geralmente, um pouco mais complexo.

Se você estiver interessado nesse tópico, aqui está (entre muitos outros) uma palestra sobre esse assunto:
http://undergraduate.csse.uwa.edu.au/units/CITS3211/lectureNotes/14.pdf

Sylvain Leroux
fonte
7

Fazemos isso o tempo todo na programação orientada a objetos. Se dois objetos se referirem um ao outro, direta ou indiretamente, eles são estruturas infinitamente recursivas (ou ambas fazem parte da mesma estrutura infinitamente recursiva, dependendo de como você olha para ele). É por isso que você não vê isso em algo tão primitivo quanto uma lista - porque geralmente é melhor descrever o conceito como "objetos" interconectados do que uma "lista infinita".

Você também pode obter ...um dicionário infinitamente recursivo. Digamos que você queira um dicionário dos cantos de um triângulo, em que cada valor seja um dicionário dos outros cantos conectados a esse canto. Você pode configurá-lo assim:

a = {}
b = {}
c = {}
triangle = {"a": a, "b": b, "c": c}
a["b"] = b
a["c"] = c
b["a"] = a
b["c"] = c
c["a"] = a
c["b"] = b

Agora, se você imprimir triangle(ou aou bou cpara que o assunto), você verá que é cheio de {...}porque nenhum dois cantos nos referindo a volta para o outro.

nmclean
fonte
Exemplo de dicionário mais simples:a = {}; a['a'] = a; print a['a']['a']['a']
user650654
Para mim, em vez de "...", ele mostra "<Recursão no ditado com id = ___>"
Solomon Ucko
@SolomonUcko Você provavelmente está usando o IPython, que usa automaticamente o pprint para imprimir coisas. Se você digitar %pprintpara desativar a impressão bonita, será exibido ....
nmclean
4

Como eu entendi, este é um exemplo de ponto fixo

p  = [1, 2]
p[1:1] = [p]
f = lambda x:x[1]
f(p)==p
f(f(p))==p
Hanfei Sun
fonte
Não consegui entender isso. Tentei executar esses comandos, mas há erros.
Aseem Bansal
@Zel: Bem, você precisa adicionar o código OP antes dele, para que p seja declarado.
Inkane
1
@Zel: Bem, eu não tenho certeza do quanto isso é útil, mas a Firegun diz que p (e, portanto, p [1], representado como [...]) é um ponto fixo da função f. IMHO, esta é uma resposta possível da pergunta "O que é [...]?" nesse caso.
Inkane
1
Eu tive o mesmo problema de erro, porque eu tentei este exemplo depois de tentar o p = [1]; p[0] = pexemplo mais simples que precisa f = lambda x:x[0]funcionar. É um exemplo de ponto de correção, mas ainda não consegui ver como isso é útil. O valor real do ponto de correção está chegando a ele de algum outro ponto de maneira recursiva ou iterativa. Um exemplo que mostra como usar a estrutura de lista da pergunta original para criar o combinador Y seria útil se possível.
dansalmo
1
q = lambda: qfaz uma lambda infinitamente exigível
whackamadoodle3000
-2

O nome desse objeto especial é reticências. Eu acho que ele é implementado como um objeto singleton no intérprete / VM do Python - algo como None - um tipo de sentinela. Como você viu, é uma maneira do Python representar a referência de uma lista dentro de si.

Jim Dennis
fonte
Estranhamente, parece não haver maneira de instanciar diretamente um objeto de reticências. O nome não é exposto pela interface Builtins, por exemplo. Portanto, você pode ver referências ao termo em certos erros (exceções levantadas), por exemplo, se tentar extrair um item usando reticências como índice. Mas você pode apenas dizer: el = Ellipsis () nem nada assim (que eu encontrei).
Jim Dennis
9
Na verdade, isso não tem nada a ver com o objeto Reticências. É apenas a string literal "[...]", que é impressa quando um ciclo é detectado durante a impressão de uma lista. Veja o código: hg.python.org/cpython/file/84d6c1c0665e/Objects/…
Jeremy Sharpe