Confusing […] List in Python: What is it?

纵然是瞬间 提交于 2019-12-17 06:53:31

问题


So I was writing up a simple binary tree in Python and came across [...]

I don't believe this to be related to the Ellipsis object, more it seems to have something to do with an infinity loop (due to Python's shallow copy?). The source of this infinity loop and why it doesn't get expanded while expanding when accessed is something I'm completely lost to, however

>>> 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, [...], [...]]

Version using a+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

version using [a,b]

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

So what exactly is [...]?


回答1:


It can also appear if you have a circular structure with a list pointing to itself. Like this:

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

Since python can't print out the structure (it would be an infinite loop) it uses the ellipsis to show that there is recursion in the structure.


I'm not quite sure if the question was what what going on or how to fix it, but I'll try to correct the functions above.

In both of them, you first make two recursive calls, which add data to the list y, and then AGAIN append the returned data to y. This means the same data will be present several times in the result.

Either just collect all the data without adding to any y, with something like

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

or just do the appending in the calls, with something like

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

(Of course, both these snippets need handling for empty lists etc)

@Abgan also noted that you really don't want y=[] in the initializer.




回答2:


I believe, that your 'tree' contains itself, therefore it contains cycles.

Try this code:

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

The first print outputs:

  [1,2,3,4]

while the second:

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

The reason is using

 def Keys(x,y=[]):
 
This is wrong and evil. List is a mutable object, and when used as a default parameter, it is preserved between function calls. So each y += "anything" operation adds to the same list (in all function calls, and since the function is recursive...)

See the Effbot or Devshed for more details on mutable objects passed as default values for functions.




回答3:


I don't understand your code above, but the [...] I think is the Python interpreter skipping infinite data structures. For example:

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

It looks like your tree structure is becoming looped.

The answers about slice objects are beside the point.




回答4:


I don't believe this to be related to the Ellipsis object, more it seems to have something to do with an infinity loop (due to Python's shallow copy?). The source of this infinity loop and why it doesn't get expanded while expanding when accessed is something I'm completely lost to, however

Look at the following code:

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

How is Python supposed to print a? It is a list that contains a zero and a reference to itself. Hence it is a list that contains a zero and a reference to a list

[0, [...]]

which in turn contains a zero and a reference to a list

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

which in turn contains a zero and a reference to a list, and so on, recursively:

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

There is nothing wrong with the recursive data structure itself. The only problem is that it cannot be displayed, for this would imply an infinite recursion. Hence Python stops at the first recursion step and deals with the infinity issue printing only the ellipsis, as was pointed out in previous answers.




回答5:


If you would have used a PrettyPrinter, the output would had been self explanatory

>>> 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

In other words its something like




回答6:


EDIT: As mentioned above, this isn't the Ellipsis object, but the result of a looped list. I jumped the gun here. Knowing about the Ellipsis object is a good bit of back shelf knowledge should you find an Ellipsis in some actual code, rather than the output.


The Ellipsis object in Python is used for extended slice notation. It's not used in current Python core libraries, but is available for developers to define in their own libraries. For example, NumPy (or SciPy) use this as part of their array object. You'll need to look at the documentation for tree() to know exactly how Ellipsis behaves in this object.

From Python documentation:

3.11.8 The Ellipsis Object

This object is used by extended slice notation (see the Python Reference Manual). It supports no special operations. There is exactly one ellipsis object, named Ellipsis (a built-in name).

It is written as Ellipsis.




回答7:


Ok, so in points:

  1. You're creating infinite data structure:

    def Keys(x,y=[])
    will use the same 'y' in each call. This just isn't correct.
  2. The print statement, however, is clever enough not to print an infinite data, but to mark self-reference with a [...] (known as Ellipsis)

  3. The Python will allow you to address such structure correctly, so you can write
    a.keys()[1][1][1]
    and so on. Why shouldn't you?
  4. The y = y[:] statement simply copies the list y. Can be done more soundly with y = list(y)

Try using the following code:

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

But still I guess that it can bite you. You're still using the same variable y (I mean the same object) in three places in one expression:

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

Is that what you really want to achieve? Or maybe you should try:

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:


For the difference between the two versions of the function Keys, note the following difference:

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

The right side value in this statement is a list which contains x[2], plus the ELEMENTS OF Keys(x[0],y) and the ELEMENTS OF Keys(x[1],y)

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

The right side value in this statement is a list which contains x[2], plus the LIST Keys(x[2],y) and the LIST Keys(x[1],y).

So the version using [a,b] will causing y contains itself as its elements.

Some other notes:

  1. Since in python, the default value object is created once when the function is defined, the first version will not work like the example shows. It will contain multiple copy of some keys. It's hard to explain in short, but you can get some idea by printing the values of x, y on each call of Keys.

    This is confirmed by running the function on my machine with python 2.5.2.

  2. Also because the default value is defined only once at function definition time, even the function works correct for the first time, it will not work when calling with a different a, since the keys in the first binary tree will remain in y.

    You can see this by calling Keys(a) twice, or calling it on two different lists.

  3. The second parameter is not required for this problem. The function can be like this:

    def Keys(a): if a = []: return [] else: return [a[2]]+Keys(a[0])+Keys(a[1])

    Defining a recursive function basically contains two part, solve subproblems and combined the results. In your code, the combining results part is repeated twice: one by accumulating them in y, one by adding the list together.




回答9:


The issue is because one of the list element is referencing the list itself. So if an attempt to print all the elements is made then it would never end.

Illustration:

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

Output:

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

x[3] is a referring to x itself. Same goes for x[3][3].

This can be visualized better here



来源:https://stackoverflow.com/questions/397034/confusing-list-in-python-what-is-it

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!