不使用 isinstance() 的列表列表的递归

发布于 2024-11-04 17:04:50 字数 632 浏览 0 评论 0原文

我刚刚读过 “isinstance() 被认为有害”,这似乎是合理的。简而言之,它主张避免使用此功能。

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

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

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

根据这篇文章,我想知道是否有一个简单的方法不使用 isinstance() 进行递归的方法...

有人知道吗?

I have just read "isinstance() considered harmful", and it seems reasonable. In short, it argues for avoiding the use of this function.

Well, just now I happen to be writing a program which takes inputs structured as a tree, and needs the tree's structure information. Without time to implement a GUI, I impose on the user to write it to a configuration file (I know this is a bad interface, but the schedule is really tight). My users are very technical, but don't necessarily know python. I chose that the file will contain lists of lists (of lists of lists etc) representing the input trees, with the final elements being the leaf nodes of the trees. I think this is much better than imposing the synthax of dictionaries on users.

I plan to parse the lists recursively as the following (ommiting the use of the tree's structure, let's simplify and say treatLeafNode() must be called on each leaf node):

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

In light of the article, I'm wondering if there is a simple way to recurse over that without using isinstance()...

Does anyone know one?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

没有你我更好 2024-11-11 17:04:57

您选择列表列表作为首选树结构是否有原因?我可以想到很多更好的方法来在配置文件中编写一个。假设您正在尝试编码:

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

Is there a reason that you've chosen a list of lists as your preferred tree structure? I can think of many better ways to write one in a config file. Suppose you are trying to encode:

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

How about

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

You can parse that into a dictionary pretty easily, and join it up into a tree. In fact, I think ConfigParser will already do it for you.

Or else, how about:

a
----b
--------c
--------d
------------e
------------f
--------g
------------h
----i
----j
--------k
平定天下 2024-11-11 17:04:56

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

Your situation is one of those where I would use isinstance. Your data structure is well-constrained, and you need to distinguish between a list and not a list. Use isinstance to ask if it is a list. You don't say, but I imagine strings might be among the leaves of your tree, and they are iterable as lists are, so it's fiddly to distinguish between them in duck-typing ways.

多孤肩上扛 2024-11-11 17:04:56

您可以使用

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

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

You could use

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

Note that this will also iterate over strings though.

灯角 2024-11-11 17:04:56

更好的方法是用 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)

请注意,这是对树的深度优先搜索。

可能有更好的方法来包装它,使 parseTree 成为 Node 的方法,但这应该给您一个想法。当然,您仍然遇到一个问题,您要求用户编写Python代码,该代码是列表的列表作为输入,并将其解析为上面的树结构,您需要使用isinstance 。也许 yaml 是描述语言的更好选择,因为用户无法将任意 Python 代码注入到您的输入中?

What might work better is encapsulating your tree structure with a Node object which can hold a value and a list of children:

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

Now a node is explicitly either a leaf with a value or an element with children (technically, non-leaf nodes can also have values in this example, but your application code can choose to enforce that non-leaf nodes never have values). parseTree can be written as:

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

Note that this is a depth-first search on the tree.

There may be nicer ways to wrap this up so that parseTree is a method of Node, but this should give you an idea. Of course you still have the problem that you're asking the user to write Python code which is lists of lists as the input, and to parse that into the above tree structure you'd need to use isinstance. Perhaps yaml would be a better choice of description language, as the users cannot then inject arbitrary Python code into your input?

伴我心暖 2024-11-11 17:04:56

使用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']]]

How about using yaml? You wont have to do the validation and the parsing logic yourself too.

The Tree could look like

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

Code to parse it

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

Output:

[[['aMAN'], ['sTACK', 'OVER'], ['FLOW']], [['aMAN1'], ['sTACK1', 'OVER1'], ['FLOW1']], [['aMAN2'], ['sTACK2', 'OVER2'], ['FLOW2']]]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文