我正在尝试在Python中创建一个二叉树,其中每个节点都有一个关联的元组(a, b)
。我只想创建一次节点对象,当我随后访问它们时,我想访问先前创建的节点对象(因为我想修改它们中的一些变量)。
目前,我正在使用节点对象的字典,以及用于创建节点的“工厂方法”。我从不打电话给Node(a, b)
;如果需要,工厂方法可以。代码是
existing_nodes = {}
class Node:
def __init__(self, a, b):
# stuff
existing_nodes.update([((a, b), self)])
def get_node(a, b):
return existing_nodes.get((a, b), Node(a, b))
但是当我在其余代码的多个位置尝试get_node(0, 0)
时,它会给我不同的对象。如果我在一个引用中修改变量,则它不会显示在其他引用中。另外,如果我print
,则会显示不同的地址。
出了什么问题?如何为节点对象创建引用字典?
答案 0 :(得分:2)
您首先创建一个Node()
实例,只有然后测试字典中的(a, b)
元组。 Python解析你的表达式:
existing_nodes.get((a, b), Node(a, b))
像这样:
t = (a, b)
n = Node(a, b)
existing_nodes.get(t, n)
(但未指定t
和n
),但调用Node(a, b)
会将self
添加到同一字典中。这样,每次调用工厂函数时都会替换上一个节点。
不要从Node.__init__
向字典添加节点。请改用dict.setdefault()
;如果找不到密钥,它会为你添加默认字典:
class Node:
def __init__(self, a, b):
# stuff
def get_node(a, b):
return existing_nodes.setdefault((a, b), Node(a, b))
这仍然会每次创建一个新的Node()
,但只有在缺少元组时才会返回它。您可以通过首先测试密钥来完全避免这种情况:
def get_node(a, b):
if (a, b) not in existing_nodes:
existing_nodes[a, b] = Node(a, b)
return existing_nodes[a, b]
您可以从Node.__new__
函数执行此操作,而不必使用工厂函数:
class Node(object):
_existing_nodes = {}
def __new__(cls, a, b):
if (a, b) not in cls._existing_nodes:
cls._existing_nodes[a, b] = super(Node, cls).__new__(cls, a, b)
return cls._existing_nodes[a, b]
def __init__(self, a, b):
# stuff