没有isinstance()的列表列表的递归

时间:2011-05-04 11:37:38

标签: python isinstance

我刚读过"isinstance() considered harmful",看起来很合理。简而言之,它主张避免使用这个功能。

好吧,刚才我正在编写一个程序,它将输入结构化为树,并且需要树的结构信息。没有时间实现GUI,我强加给用户将其写入配置文件(我知道这是一个糟糕的接口,但时间表非常紧张)。我的用户非常技术,但不一定知道python。我选择该文件将包含表示输入树的列表(列表列表等)列表,最终元素是树的叶节点。我认为这比在用户上强加字典的合成要好得多。

我打算递归地解析列表如下(省略树的结构的使用,让我们简化并说必须在每个叶子节点上调用treatLeafNode()):

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

根据这篇文章,我想知道是否有一种简单的方法可以在不使用isinstance()的情况下进行递归...

有人知道吗?

5 个答案:

答案 0 :(得分:10)

您的情况是我使用isinstance的情况之一。您的数据结构受到很好的约束,您需要区分列表而不是列表。使用isinstance询问它是否为列表。你没有说,但是我想象字符串可能在树的叶子中,并且它们可以像列表那样迭代,所以用鸭子打字方式来区分它们是非常繁琐的。

答案 1 :(得分:5)

您可以使用

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

请注意,这也会迭代字符串。

答案 2 :(得分:2)

更好的方法是使用Node对象封装树结构,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代码?

答案 3 :(得分: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']]]

答案 4 :(得分: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