Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #81170 > unrolled thread

Infinitely nested containers

Started byGill Shen <gillarete@gmail.com>
First post2014-11-20 21:54 -0800
Last post2014-11-21 10:13 -0700
Articles 18 — 10 participants

Back to article view | Back to comp.lang.python


Contents

  Infinitely nested containers Gill Shen <gillarete@gmail.com> - 2014-11-20 21:54 -0800
    Re: Infinitely nested containers Marko Rauhamaa <marko@pacujo.net> - 2014-11-21 09:00 +0200
      Re: Infinitely nested containers random832@fastmail.us - 2014-11-21 12:39 -0500
        Re: Infinitely nested containers Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2014-11-22 15:43 +1100
          Re: Infinitely nested containers Chris Angelico <rosuav@gmail.com> - 2014-11-22 15:50 +1100
            Re: Infinitely nested containers Rustom Mody <rustompmody@gmail.com> - 2014-11-21 21:02 -0800
              Re: Infinitely nested containers Chris Angelico <rosuav@gmail.com> - 2014-11-22 16:09 +1100
                Re: Infinitely nested containers Rustom Mody <rustompmody@gmail.com> - 2014-11-21 22:03 -0800
          Re: Infinitely nested containers Ethan Furman <ethan@stoneleaf.us> - 2014-11-22 11:50 -0800
            Re: Infinitely nested containers Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2014-11-23 16:59 +1100
              Re: Infinitely nested containers random832@fastmail.us - 2014-11-23 01:39 -0500
      Re: Infinitely nested containers Chris Angelico <rosuav@gmail.com> - 2014-11-22 04:47 +1100
      Re: Infinitely nested containers random832@fastmail.us - 2014-11-21 12:50 -0500
      Re: Infinitely nested containers Ian Kelly <ian.g.kelly@gmail.com> - 2014-11-21 11:37 -0700
      Re: Infinitely nested containers Zachary Ware <zachary.ware+pylist@gmail.com> - 2014-11-21 13:30 -0600
      Re: Infinitely nested containers Terry Reedy <tjreedy@udel.edu> - 2014-11-22 16:57 -0500
    Re: Infinitely nested containers Chris Angelico <rosuav@gmail.com> - 2014-11-21 18:03 +1100
    Re: Infinitely nested containers Ian Kelly <ian.g.kelly@gmail.com> - 2014-11-21 10:13 -0700

#81170 — Infinitely nested containers

FromGill Shen <gillarete@gmail.com>
Date2014-11-20 21:54 -0800
SubjectInfinitely nested containers
Message-ID<931d12c0-12b3-4278-a9b9-1e2c32f138b3@googlegroups.com>
Purely out of curiosity I tried this (on 2.7.3):

>>> ls = []
>>> ls.append(ls)
>>> ls
[[...]]


The list appears to be ... infinitely nested:

>>> ls == ls[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]
True


Similar things can be done with non-empty list and dict:

>>> ls2 = [1]
>>> ls2.append(ls2)
>>> ls2
[1, [...]]
>>> ls2 == ls2[1] == ls2[1][1] 
True
>>> d = {}
>>> d[0] = d
>>> d
{0: {...}}
>>> d == d[0] == d[0][0]
True


How is this behavior implemented under the hood? And why is this allowed at all? Is it just a curiosity or can you do something useful with it?

[toc] | [next] | [standalone]


#81173

FromMarko Rauhamaa <marko@pacujo.net>
Date2014-11-21 09:00 +0200
Message-ID<87bno16nsw.fsf@elektro.pacujo.net>
In reply to#81170
Gill Shen <gillarete@gmail.com>:

> How is this [nesting] behavior implemented under the hood?

Pointers.

> And why is this allowed at all?

There's no reason not to.

> Is it just a curiosity or can you do something useful with it?

It absolutely does arise every here and there. It's so natural you don't
even pay attention to it.


Marko

[toc] | [prev] | [next] | [standalone]


#81230

Fromrandom832@fastmail.us
Date2014-11-21 12:39 -0500
Message-ID<mailman.16114.1416591558.18130.python-list@python.org>
In reply to#81173
On Fri, Nov 21, 2014, at 02:00, Marko Rauhamaa wrote:
> Gill Shen <gillarete@gmail.com>:
> 
> > How is this [nesting] behavior implemented under the hood?
> 
> Pointers.
> 
> > And why is this allowed at all?
> 
> There's no reason not to.

There's no reason not to allow it with tuples, but you can't do it.
Mainly because doing it in a single literal would require special
syntax, whereas you can simply append to a list a reference to itself.

I think I tried on at least one python version and printing the tuple
crashed with a recursion depth error, since it had no special protection
for this case the way list printing does.

[toc] | [prev] | [next] | [standalone]


#81267

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2014-11-22 15:43 +1100
Message-ID<54701468$0$12986$c3e8da3$5496439d@news.astraweb.com>
In reply to#81230
random832@fastmail.us wrote:

> On Fri, Nov 21, 2014, at 02:00, Marko Rauhamaa wrote:
>> Gill Shen <gillarete@gmail.com>:
>> 
>> > How is this [nesting] behavior implemented under the hood?
>> 
>> Pointers.
>> 
>> > And why is this allowed at all?
>> 
>> There's no reason not to.
> 
> There's no reason not to allow it with tuples, but you can't do it.
> Mainly because doing it in a single literal would require special
> syntax, whereas you can simply append to a list a reference to itself.

You can't append a list to itself in a single expression, you have to create
the list first.

> I think I tried on at least one python version and printing the tuple
> crashed with a recursion depth error, since it had no special protection
> for this case the way list printing does.


It works fine now (Python 3.3).

py> L = []
py> t = (L, None)
py> L.append(L)
py> L.append(t)  # For good measure.
py> print(t)
([[...], (...)], None)


but yes, in old versions of Python printing self-recursive containers may
break.



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#81268

FromChris Angelico <rosuav@gmail.com>
Date2014-11-22 15:50 +1100
Message-ID<mailman.16134.1416631815.18130.python-list@python.org>
In reply to#81267
On Sat, Nov 22, 2014 at 3:43 PM, Steven D'Aprano
<steve+comp.lang.python@pearwood.info> wrote:
> random832@fastmail.us wrote:
>
>> There's no reason not to allow it with tuples, but you can't do it.
>> Mainly because doing it in a single literal would require special
>> syntax, whereas you can simply append to a list a reference to itself.
>
> You can't append a list to itself in a single expression, you have to create
> the list first.

It's possible to have a list directly refer to itself:

lst = []
lst.append(lst)

It's not possible, with pure Python code, to create a tuple with a
reference to itself, because you have to create a tuple with a single
expression. Hence the comments about using the C API... and breaking
stuff.

ChrisA

[toc] | [prev] | [next] | [standalone]


#81269

FromRustom Mody <rustompmody@gmail.com>
Date2014-11-21 21:02 -0800
Message-ID<4cecd824-19c6-4be3-b91b-06602313d0ae@googlegroups.com>
In reply to#81268
On Saturday, November 22, 2014 10:20:36 AM UTC+5:30, Chris Angelico wrote:
> On Sat, Nov 22, 2014 at 3:43 PM, Steven D'Aprano wrote:
> > random832 wrote:
> >
> >> There's no reason not to allow it with tuples, but you can't do it.
> >> Mainly because doing it in a single literal would require special
> >> syntax, whereas you can simply append to a list a reference to itself.
> >
> > You can't append a list to itself in a single expression, you have to create
> > the list first.
> 
> It's possible to have a list directly refer to itself:
> 
> lst = []
> lst.append(lst)

Thats not a single expression; which is possible with a lazy
evaluation language like Haskell.
Prelude> let ones = 1 : ones
Prelude> ones
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
<until the Control-C>

[toc] | [prev] | [next] | [standalone]


#81271

FromChris Angelico <rosuav@gmail.com>
Date2014-11-22 16:09 +1100
Message-ID<mailman.16135.1416633006.18130.python-list@python.org>
In reply to#81269
On Sat, Nov 22, 2014 at 4:02 PM, Rustom Mody <rustompmody@gmail.com> wrote:
> Thats not a single expression; which is possible with a lazy
> evaluation language like Haskell.
> Prelude> let ones = 1 : ones

I'm not sure "lazy evaluation" is the key here, unless it also does
name lookups lazily. What happens if you do this:

let foo = 1 : bar
let bar = 2 : 3
foo

Will that show 1, 2, 3? If so, then sure, lazy eval is what achieved
that - but it's also going to make it hard to track down name errors.

ChrisA

[toc] | [prev] | [next] | [standalone]


#81275

FromRustom Mody <rustompmody@gmail.com>
Date2014-11-21 22:03 -0800
Message-ID<3b7cae0e-8e3e-43a5-a5ee-767a3df867c8@googlegroups.com>
In reply to#81271
On Saturday, November 22, 2014 10:40:23 AM UTC+5:30, Chris Angelico wrote:
> On Sat, Nov 22, 2014 at 4:02 PM, Rustom Mody  wrote:
> > Thats not a single expression; which is possible with a lazy
> > evaluation language like Haskell.
> > Prelude> let ones = 1 : ones
> 
> I'm not sure "lazy evaluation" is the key here, unless it also does
> name lookups lazily. What happens if you do this:
> 
> let foo = 1 : bar
> let bar = 2 : 3
> foo
> 
> Will that show 1, 2, 3? If so, then sure, lazy eval is what achieved
> that - but it's also going to make it hard to track down name errors.

Prelude> let foo = 1 : bar; bar = 2 : [3]
Prelude> foo
[1,2,3]


Prelude> let foo = 1 : bar; bar = 2 : foo
Prelude> foo
[1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1 <Control-C>

[toc] | [prev] | [next] | [standalone]


#81300

FromEthan Furman <ethan@stoneleaf.us>
Date2014-11-22 11:50 -0800
Message-ID<mailman.16142.1416685847.18130.python-list@python.org>
In reply to#81267

[Multipart message — attachments visible in raw view] — view raw

On 11/21/2014 08:43 PM, Steven D'Aprano wrote:
> random832@fastmail.us wrote:
>> 
>> I think I tried on at least one python version and printing the tuple
>> crashed with a recursion depth error, since it had no special protection
>> for this case the way list printing does.
> 
> It works fine now (Python 3.3).
> 
> py> L = []
> py> t = (L, None)
> py> L.append(L)
> py> L.append(t)  # For good measure.
> py> print(t)
> ([[...], (...)], None)

This is a tuple in a list in a tuple, not a tuple in a tuple.

--
~Ethan~

[toc] | [prev] | [next] | [standalone]


#81330

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2014-11-23 16:59 +1100
Message-ID<547177a5$0$12989$c3e8da3$5496439d@news.astraweb.com>
In reply to#81300
Ethan Furman wrote:

> On 11/21/2014 08:43 PM, Steven D'Aprano wrote:
>> random832@fastmail.us wrote:
>>> 
>>> I think I tried on at least one python version and printing the tuple
>>> crashed with a recursion depth error, since it had no special protection
>>> for this case the way list printing does.
>> 
>> It works fine now (Python 3.3).
>> 
>> py> L = []
>> py> t = (L, None)
>> py> L.append(L)
>> py> L.append(t)  # For good measure.
>> py> print(t)
>> ([[...], (...)], None)
> 
> This is a tuple in a list in a tuple, not a tuple in a tuple.

Really? I hadn't noticed.

*wink*

It's still a tuple in itself, recursively, and the tuple to str conversion
routine still has to deal with the fact.




-- 
Steven

[toc] | [prev] | [next] | [standalone]


#81337

Fromrandom832@fastmail.us
Date2014-11-23 01:39 -0500
Message-ID<mailman.16163.1416724802.18130.python-list@python.org>
In reply to#81330

On Sun, Nov 23, 2014, at 00:59, Steven D'Aprano wrote:
> >> It works fine now (Python 3.3).
> >> 
> >> py> L = []
> >> py> t = (L, None)
> >> py> L.append(L)
> >> py> L.append(t)  # For good measure.
> >> py> print(t)
> >> ([[...], (...)], None)
> > 
> > This is a tuple in a list in a tuple, not a tuple in a tuple.
> 
> Really? I hadn't noticed.
> 
> *wink*
> 
> It's still a tuple in itself, recursively, and the tuple to str
> conversion
> routine still has to deal with the fact.

Does it, or does it punt to the list to str routine?

Anyway, on python 2.7, print and str do not work the same way for
tuples. I'm remembering more about this issue now, and it was _strictly_
on print, not on str.
>>> t
([[...], ([...], None)], None)
>>> print(t)
([[...], ([...], None)], None)
>>> str(t)
'([[...], (...)], None)'


Notice that print never does (...), only [...]. And if it never finds a
[...]?

[toc] | [prev] | [next] | [standalone]


#81232

FromChris Angelico <rosuav@gmail.com>
Date2014-11-22 04:47 +1100
Message-ID<mailman.16116.1416592077.18130.python-list@python.org>
In reply to#81173
On Sat, Nov 22, 2014 at 4:39 AM,  <random832@fastmail.us> wrote:
> There's no reason not to allow it with tuples, but you can't do it.
> Mainly because doing it in a single literal would require special
> syntax, whereas you can simply append to a list a reference to itself.
>
> I think I tried on at least one python version and printing the tuple
> crashed with a recursion depth error, since it had no special protection
> for this case the way list printing does.

You can do it in C, I believe - PyTuple_New() followed by
PyTuple_SetItem(x, 0, x) should do it.

ChrisA

[toc] | [prev] | [next] | [standalone]


#81233

Fromrandom832@fastmail.us
Date2014-11-21 12:50 -0500
Message-ID<mailman.16117.1416592205.18130.python-list@python.org>
In reply to#81173
On Fri, Nov 21, 2014, at 12:47, Chris Angelico wrote:
> You can do it in C, I believe - PyTuple_New() followed by
> PyTuple_SetItem(x, 0, x) should do it.

Yeah, that's how I did it. I think python 2 crashed and python 3
didn't... or maybe it was the interactive interpreter that crashed and
calling repr didn't, within the same version - I don't remember that
well.

[toc] | [prev] | [next] | [standalone]


#81236

FromIan Kelly <ian.g.kelly@gmail.com>
Date2014-11-21 11:37 -0700
Message-ID<mailman.16119.1416595105.18130.python-list@python.org>
In reply to#81173
On Fri, Nov 21, 2014 at 10:39 AM,  <random832@fastmail.us> wrote:
> On Fri, Nov 21, 2014, at 02:00, Marko Rauhamaa wrote:
>> Gill Shen <gillarete@gmail.com>:
>>
>> > How is this [nesting] behavior implemented under the hood?
>>
>> Pointers.
>>
>> > And why is this allowed at all?
>>
>> There's no reason not to.
>
> There's no reason not to allow it with tuples, but you can't do it.
> Mainly because doing it in a single literal would require special
> syntax, whereas you can simply append to a list a reference to itself.
>
> I think I tried on at least one python version and printing the tuple
> crashed with a recursion depth error, since it had no special protection
> for this case the way list printing does.

Here's a nice crash. I thought this might similarly produce a
recursion depth error, but no, it's a seg fault!

$ cat test.py
import itertools

l = []
it = itertools.chain.from_iterable(l)
l.append(it)
next(it)
$ python3 test.py
Segmentation fault (core dumped)

[toc] | [prev] | [next] | [standalone]


#81239

FromZachary Ware <zachary.ware+pylist@gmail.com>
Date2014-11-21 13:30 -0600
Message-ID<mailman.16122.1416598274.18130.python-list@python.org>
In reply to#81173
On Fri, Nov 21, 2014 at 12:37 PM, Ian Kelly <ian.g.kelly@gmail.com> wrote:
> Here's a nice crash. I thought this might similarly produce a
> recursion depth error, but no, it's a seg fault!
>
> $ cat test.py
> import itertools
>
> l = []
> it = itertools.chain.from_iterable(l)
> l.append(it)
> next(it)
> $ python3 test.py
> Segmentation fault (core dumped)

Would you mind submitting a bug report for that?  Any segfault
produced by pure Python code must be fixed.

-- 
Zach

[toc] | [prev] | [next] | [standalone]


#81303

FromTerry Reedy <tjreedy@udel.edu>
Date2014-11-22 16:57 -0500
Message-ID<mailman.16145.1416693495.18130.python-list@python.org>
In reply to#81173
On 11/21/2014 2:30 PM, Zachary Ware wrote:
> On Fri, Nov 21, 2014 at 12:37 PM, Ian Kelly <ian.g.kelly@gmail.com> wrote:
>> Here's a nice crash. I thought this might similarly produce a
>> recursion depth error, but no, it's a seg fault!
>>
>> $ cat test.py
>> import itertools
>>
>> l = []
>> it = itertools.chain.from_iterable(l)
>> l.append(it)
>> next(it)
>> $ python3 test.py
>> Segmentation fault (core dumped)
>
> Would you mind submitting a bug report for that?  Any segfault
> produced by pure Python code must be fixed.

This is too important to lose.
http://bugs.python.org/issue22920


-- 
Terry Jan Reedy

[toc] | [prev] | [next] | [standalone]


#81175

FromChris Angelico <rosuav@gmail.com>
Date2014-11-21 18:03 +1100
Message-ID<mailman.16085.1416553437.18130.python-list@python.org>
In reply to#81170
On Fri, Nov 21, 2014 at 4:54 PM, Gill Shen <gillarete@gmail.com> wrote:
> How is this behavior implemented under the hood? And why is this allowed at all? Is it just a curiosity or can you do something useful with it?

Simple: The list contains itself. When you dereference the list, you
get back the original list. It does have value; you just have to be
careful of any recursive operation like printing it out - the repr()
for a list carefully checks for this.

ChrisA

[toc] | [prev] | [next] | [standalone]


#81229

FromIan Kelly <ian.g.kelly@gmail.com>
Date2014-11-21 10:13 -0700
Message-ID<mailman.16113.1416590068.18130.python-list@python.org>
In reply to#81170
On Thu, Nov 20, 2014 at 10:54 PM, Gill Shen <gillarete@gmail.com> wrote:
> How is this behavior implemented under the hood? And why is this allowed at all? Is it just a curiosity or can you do something useful with it?

Reference cycles are common in Python and other OO languages. For
example, adding a widget to a window; the window contains references
to its child widgets, and it's probably useful for the widgets to know
what their parents are, so they would hold references back.

A list containing itself is similarly a reference cycle. I don't know
off-hand of any use for this specific case, but it's just a slightly
tighter cycle than normal.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web