2011-08-31 79 views
2

基本上,我試圖在我的函數中展開一個列表,但忽略它(您也可以忽略我放入的打印函數)。 以x = [[1,2,3],4,5]爲我的變量。 我打電話prob7(x)但問題是,當type([1,2,3])得到檢查==列表,它返回false。這是爲什麼?我明確地檢查瞭解釋器命令行上的內容,並且它返回true。但在函數內部,我弄錯了。Python的邏輯錯誤?

只是我錯過了一個錯誤,因爲我很困或者我誤解了Python語言的某些部分?如果它很重要,我運行2.6版本。

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

當心列表嵌套多於'sys.getrecursionlimit()'(約1000列出)深。由於您在嵌套列表上調用函數,因此您可以按遞歸深度限制並獲得RecursionError。 –

+0

dang,謝謝大家。比我需要的更多的信息,但仍然非常有用 – dtc

回答

3

只是不使用'list'作爲變量名並使用isinstance(var,list)而不是type(var)== list。 請在下面找到更正的樣本。

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 

或者,如果你真的不要求使用遞歸,你不關心值順序,那麼你可以使用這樣的事情:

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] 
+1

在迭代之前檢查空列表是無用的:遍歷空列表將無法正確執行任何操作。特殊情況不夠特殊。 –

+0

@Karl - 當然 - 我只是試圖修復OP示例,我的代碼是第二個。 –

+0

如果我使用type()==,爲什麼使用isinstance?我以爲你只需要那個子類 – dtc

0

這裏的問題是你用的是局部變量名稱(列表),與全局的list類型相同。你應該改變你的變量名稱。另外,檢查類型時,可以使用is運算符。

type(l) is list 

但這是我的flatten版本。

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

這不會改變原始列表,但會返回一個新列表。這與大多數其他模式一致。

+0

謝謝你,這裏最清楚的答案,但我會檢查出isinstance的東西。 – dtc

3

Artisom有你的答案。另外,類型檢查並不是非常的Pythonic。 Duck typing往往是要走的路。如果您的要素僅是數字,下面做工作也沒有明確的類型檢查,但檢查的行爲:

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

注意在此實現的字符串元素會表現得像嵌套列表。無論如何,只是想說明期望行爲的意思,而不是類型。

+0

'+ ='列表有點被黑客入侵。使字符串「行爲」的最簡單方法就是使用'outlist = outlist + x'。是的,特別是'list'類型,這不是等價的。無論如何,這隻會拉平一個級別。 –

+0

的確,'outlist.extend(...)'在這裏可能會更好。是的,'outline + x'按照預期的方式工作,但也會爲元組元素引發TypeErrors,並且它總是會創建新的列表對象。我選擇了*一級*解決方案來主要說明鴨子打字的想法。對於一個真正的遞歸壓扁,在我看來,'instanceof'檢查會更明確(http://www.python.org/dev/peps/pep-0020/)。 –

+0

如果你想遞歸地展平所有可以展開的東西,我可以通過檢查'x'是否是可迭代的,然後在'x'具有已知長度爲1的情況下使用特殊外形來避免duck-type(爲了避免字符串上的無限遞歸)。 –

0

一些替代的方法:

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