【问题标题】:Python `collections.defaultdict` for the same class同一类的 Python `collections.defaultdict`
【发布时间】:2021-04-22 06:14:31
【问题描述】:

我尝试使用 Trie 数据结构来解决一些编码问题。 对于 trie 中的每个节点,您通常会放置一个其子节点的引用列表。 因此,如果查找中不存在某些子节点,我考虑使用 defaultdict 创建一个默认的空 trie 节点。 但是,我不知道如何使用 defaultdict 来引用包含它的类。

我尝试了两种方法,都失败了。以下是我尝试过的。

from dataclasses import dataclass
from collections import defaultdict

@dataclass   
class TrieNode():
    is_word = False
    children = defaultdict("TrieNode")

上面的代码产生

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 4, in TrieNode
TypeError: first argument must be callable or None
@dataclass   
class TrieNode():
    is_word = False
    children = defaultdict(TrieNode)

以上会产生

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 4, in TrieNode
NameError: name 'TrieNode' is not defined

我的问题是如何使用defaultdict 优雅地实现这一点。 非常感谢您。

【问题讨论】:

  • 为什么不使用列表?
  • 或者从trie上的维基百科条目中的代码开始?

标签: python trie defaultdict


【解决方案1】:

您使用children = defaultdict(TrieNode) 的第二种方法更接近正确,因为defaultdict 需要TrieNode 的构造函数才能使用TrieNodes 填充它 - 另一种方法传递一个预期可调用的字符串。您的问题是由于您在创建类之前访问名称 TrieNode 导致的,给出了 NameError。要解决此问题,您可以使用children = defaultdict(lambda: TrieNode())。这样,名称TrieNode 只会在调用 lambda 函数时查找。

但是,对于一个 trie,您希望每个节点都有自己的子字典,并且通过这种方法,修改一个节点的子字典将为所有节点修改它,因为它们的所有字典都是同一个对象。我建议您使用dataclass.field 为每个TrieNode 创建一个新字典,如下所示:

from dataclasses import dataclass, field
from collections import defaultdict

@dataclass   
class TrieNode():
    is_word = False
    children : 'TrieNode' = field(default_factory=lambda: defaultdict(TrieNode))

【讨论】:

  • 聪明,感谢您提供如此体面的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-11
  • 2016-06-18
  • 2011-08-19
  • 1970-01-01
  • 2011-10-19
  • 1970-01-01
相关资源
最近更新 更多