+2  A: 

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.

Jarred McCaffrey
+16  A: 

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.

CAdaker
+5  A: 

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.

Ned Batchelder
+6  A: 

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.

Abgan
Added y=y[:] to the top of the [a,b] version and got an output of [[0], [[1], [[6], [[8], [], []], [[3], [], []]], []], [[-4], [], []]]
Demur Rumed
Well, it's 4:27 a.m. in my place, so I'm not quite into following the brackets. What's wrong with the output?And you should really use "def Keys(x,y=None):if y is None: y = []" instead.
Abgan
+3  A: 

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.

Federico Ramponi
When you call a[1] you get [0,[...]] again however. In the case of my example, it seems to be returning a larger list rather than the same list. Perhaps Python is merging [...]+[...] into [...]?
Demur Rumed
When you call a[1] you get [0,[...]] again: YES, because a[1] is a itself!
Federico Ramponi
+1  A: 

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 []
Abgan
+1  A: 

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.

Quite elegant. Though I had to change a[2] to [a[2]]
Demur Rumed
Corrected. Thanks.