2011-05-04 59 views
5

我剛剛讀了"isinstance() considered harmful",這似乎是合理的。總之,它主張避免使用這個功能。在沒有isinstance的列表上遞歸遞歸()

剛纔我碰巧寫了一個程序,它把輸入結構化爲一棵樹,並且需要樹的結構信息。沒有時間來實現GUI,我強加給用戶把它寫入配置文件(我知道這是一個糟糕的界面,但時間表非常緊密)。我的用戶非常技術性,但不一定知道python。我選擇該文件將包含代表輸入樹的列表(列表等)列表,最後的元素是樹的葉節點。我認爲這比將詞典的合成詞強加給用戶好得多。

我打算遞歸解析列爲以下(ommiting利用樹的結構,讓我們簡化和說treatLeafNode()必須被調用每個葉節點上):

def parseTree(input): 
    if isinstance (input, list): 
     for item in input: 
      parseTree(item) 
    else: 
     treatLeafNode(item) 

在光文章,我想知道是否有一個簡單的方法來彌補,而不使用isinstance()...

有誰知道嗎?

回答

10

您的情況是我使用isinstance的那種情況之一。您的數據結構受到很好的約束,您需要區分列表而不是列表。使用isinstance詢問它是否是一個列表。你不會說,但我想象中的字符串可能在樹的葉子之間,而且它們可以像列表一樣迭代,所以用鴨子打字的方式來區分它們是很困難的。

+1

++,合理的建議 – 2011-05-04 12:01:02

5

你可以使用

def parseTree(input): 
    try: 
     for item in input: 
      parseTree(item) 
    except TypeError: 
     treatLeafNode(item) 

注意,這也將遍歷字符串,但。

+1

@Andrey:什麼是你的觀點? – 2011-05-04 11:45:27

+0

對不起,我錯了 – Andrey 2011-05-04 11:50:27

+1

@Sven:也許Andrey的意思是'input in input'也會成功,如果'input'是一個字符串,這個代碼就會失敗,像'[「abc」,[「rty 「,」xyz「]]' – 2011-05-04 11:53:19

2

什麼可能更好地工作與Node對象,可容納一個值和兒童的名單封裝你的樹結構:

class Node(object): 
    def __init__(self, children=[], value=None): 
     self.children = children 
     self.value = value 
    def isLeaf(self): 
     return len(self.children) == 0 

現在一個節點是明確使用一個值葉或與元素兒童(在技術上,非葉節點在這個例子中也可以有值,但是你的應用程序代碼可以選擇強制非葉節點從不具有值)。 parseTree可寫爲:

def parseTree(node): 
    if node.isLeaf(): 
     treatLeafNode(node) 
    else: 
     for child in node.children: 
      parseTree(child) 

請注意,這是對樹的深度優先搜索。

可能有更好的方法來包裝這個,所以parseTreeNode的方法,但這應該給你一個想法。當然,您仍然有問題要求用戶編寫列表的Python代碼作爲輸入,並將其解析爲上述需要使用的樹結構isinstance。也許yaml會是更好的描述語言選擇,因爲用戶不能在輸入中注入任意的Python代碼?

0

如何使用yaml?你也不必自己去做驗證和解析邏輯。

樹可能看起來像

- [[aMAN],[sTACK, OVER],[FLOW]] 
- [[aMAN1],[sTACK1, OVER1],[FLOW1]] 
- [[aMAN2],[sTACK2, OVER2],[FLOW2]] 

代碼來解析它

import yaml      
f= open('test.yml') 
test = yaml.load(f.read()) 
print test 

輸出:

[[['aMAN'], ['sTACK', 'OVER'], ['FLOW']], [['aMAN1'], ['sTACK1', 'OVER1'], ['FLOW1']], [['aMAN2'], ['sTACK2', 'OVER2'], ['FLOW2']]] 
0

是否有您所選擇的名單列表的原因你喜歡的樹結構?我可以想出許多更好的方法在配置文件中編寫一個。假設你想編碼:

a 
|-- b 
| |-- c 
| |-- d 
| | |-- e 
| | `-- f 
| `-- g 
|  `-- h 
|-- i 
`-- j 
    `-- k 

如何

a: b, i, j 
b: c, d, g 
d: e, f 
g: h 
j: k 

可以解析到字典中很容易地,並加入它變成一棵樹。事實上,我認爲ConfigParser已經爲你做到了。

否則,何談:

a 
----b 
--------c 
--------d 
------------e 
------------f 
--------g 
------------h 
----i 
----j 
--------k