dtc
dtc

Reputation: 1849

Python logic error?

Basically, I'm trying to flatten a list in my function but ignore that (you can also ignore the print functions I put in). take x = [[1,2,3],4,5] to be my variable. I call prob7(x) but the issue is that when type([1,2,3]) gets checked == list, it returns false. Why is that? I explicitly check this on the interpreter command line and it returns true. But inside the function, I get a false.

Just a bug that I missed because I'm sleepy or am I misunderstanding some part of the Python language? I run version 2.6 if it matters.

def prob7(list): # flatten a list
    tempList = []
    if list: # meaning if there are elements in the list and it is not empty
        for i in list:
            if type(i) != list:
                print tempList,'if',i,type(i)==list
                tempList.append(i)
            else:
                print tempList,'else',i
                tempList.extend(prob7(i))

    return tempList

Upvotes: 2

Views: 1794

Answers (4)

Keith
Keith

Reputation: 43064

The problem here is you are using a local variable name (list) that is the same as the global list type. You should change your variable name. Also, when checking types like that you can use the is operator.

type(l) is list

But here's my version of flatten.

def flatten(alist):
    rv = []
    for val in alist:
        if isinstance(val, list):
            rv.extend(flatten(val))
        else:
            rv.append(val)
    return rv

This does not alter the original list, but returns a new list. This is consistent with most other patterns.

Upvotes: 0

Karl Knechtel
Karl Knechtel

Reputation: 61654

Some alternate approaches:

# Iterative, but more functional-style
def flatten(a_list):
  while any(isinstance(x, list) for x in a_list):
    a_list = sum((x if isinstance(x, list) else [x] for x in a_list), [])
  return a_list

# Using a generator recursively, 
# then evaluating the generator to produce the list
# instead of explicitly appending each element.
def flatten_gen(a_list):
  for x in a_list:
    if isinstance(x, list):
      for y in flatten_gen(x): yield y
    else: yield x

def flatten(a_list): return list(flatten_gen(a_list))

Upvotes: 0

Artsiom Rudzenka
Artsiom Rudzenka

Reputation: 29131

Just not use 'list' as a variable name and use isinstance(var, list) instead of type(var) == list. Please find corrected sample below.

def prob7(mylist): # flatten a list
    tempList = []
    if mylist: # meaning if there are elements in the list and it is not empty
        for i in mylist:
            if not isinstance(i, list):
                print tempList, 'if', i, isinstance(i, list)
                tempList.append(i)
            else:
                print tempList, 'else', i
                tempList.extend(prob7(i))    
    return tempList

Or if you don't really required to use recursion and you don't care about values order then you can use something like this:

lVals = [[1,2,3],4,5, [1,[4,7]]]

def make_flat(mylist): # flatten a list    
    while any(isinstance(x, list) for x in mylist):
        for i, val in enumerate(mylist):
            if isinstance(val, list):                
                mylist.extend(mylist.pop(i))        
                break
    return mylist

make_flat(lVals)
>>> [4, 5, 1, 2, 3, 1, 4, 7]

Upvotes: 3

Oben Sonne
Oben Sonne

Reputation: 9953

Artisom has your answer. In addtion, type checks are not very Pythonic. Duck typing often is the way to go. In case your elements are numbers only, the following does the job too, without explicit type checks but behavior checks:

def prob7(inlist): # flatten a list
    outlist = []
    for x in inlist:
        try:
            outlist += x
        except TypeError:
            outlist.append(x)
    return outlist

Note that string elements in this implementation would behave like nested lists. Anyway, just wanted to illustrate what it means to expect behavior, not types.

Upvotes: 3

Related Questions