我正在尝试按照以下说明创建有向图:https://www.geeksforgeeks.org/generate-graph-using-dictionary-python/
但是,当我尝试创建带有for循环的节点时,尽管有预期的行为,但最后我剩下的所有相同类型(使用for循环创建)的节点都是创建的最后一个节点并非如此...
我曾尝试在分配给字典时使用节点的copy.deepcopy
,但是最终无法为每个节点添加1个以上的边缘
class GraphNode
def __init__(self,
node_type: str,
node_id: str,
position: GraphNodePosition):
self.parameters = self.generate_empty_parameters(node_type)
self.type = node_type
self.id = node_id
self.position = position
def __eq__(self, other):
if self.type != other.type:
return False
if self.parameters != other.parameters:
return False
return True
def __hash__(self):
return hash(self.id)
class ApplicationGraph:
def __init__(self):
self.nodes: typing.DefaultDict[GraphNode, typing.List[GraphNode]] = collections.defaultdict(list)
def add_new_node(self, node: GraphNode) -> bool:
if node not in self.nodes.keys():
self.nodes[node] = list()
return True
else:
return False
def add_new_edge(self, source_node: GraphNode, destination_node: GraphNode) -> bool:
if source_node not in self.nodes.keys():
return False
else:
self.nodes[source_node].append(destination_node)
return True
预期:
for created_node in node_list:
graph.add_new_node(created_node["node"])
for created_edge in created_node["edges"]:
graph.add_new_edge(created_node["node"],
图将如下所示:
{
node1: [node2, node3],
node2: [node3],
node3: []
}
实际:
图最终像这样:
{
node3: []
}
编辑1:我100%确定self.id对于每个for循环分配都是唯一的
编辑2:
node_list: typing.List(dict) = [
{
"node": GraphNode object,
"edges": [GraphNode objects this node is connected to]
}
]
编辑3:
每个节点都是这样创建的:
arguments_for_id: typing.Dict[str, str]
arguments_for_node: typing.Dict[str, typing.Union[str, int, bool, float, list, dict]
foo_node = GraphNode(
node_type="foo",
node_id=GraphNode.generate_id(
node_type="foo",
**arguments_for_id
),
position=GraphNodePosition(
x=x_position,
y=y_position
)
)
# arguments_for_id are a subset of arguments_for_node
for argument_name, argument_value in arguments_for_node.items():
getattr(foo_node.parameters, argument_name).value = argument_value
编辑4:添加了arguments_for_id
和arguments_for_node
的打字说明
编辑5:generate_id
功能
def generate_id(node_type: str, **kwargs) -> str:
invalid_id = f"%INVALIDID%KWARGS:{kwargs}"
if node_type not in GraphNode.required_node_id_parameters.keys():
return invalid_id
elif not list(kwargs.keys()) == GraphNode.required_node_id_parameters[node_type]:
return invalid_id
else:
result = f"{node_type}"
for parameter_name, parameter_value in kwargs.items():
result += f"_{parameter_value}"
return result
编辑6:复制问题所需的最少代码
a = Application("foobar")
l3out_node = GraphNode(
node_type="l3out",
node_id=GraphNode.generate_id(
node_type="l3out",
application_name="foobar"
),
position=GraphNodePosition(
x=0,
y=0
)
)
l3out_node.parameters.application_name.value = "foobar"
a.graph.add_new_node(l3out_node)
tier_nodes = [
GraphNode(
node_type="tier",
node_id=GraphNode.generate_id(
node_type="tier",
application_name="foobar",
tier_name="foo"
),
position=GraphNodePosition(
x=100,
y=100
)
),
GraphNode(
node_type="tier",
node_id=GraphNode.generate_id(
node_type="tier",
application_name="foobar",
tier_name="bar"
),
position=GraphNodePosition(
x=100,
y=-100
)
),
]
tier_nodes[0].parameters.application_name.value = "foobar"
tier_nodes[0].parameters.tier_name.value = "foo"
tier_nodes[1].parameters.application_name.value = "foobar"
tier_nodes[1].parameters.tier_name.value = "bar"
for tier_node in tier_nodes:
a.graph.add_new_node(tier_node)
a.graph.add_new_edge(l3out_node, tier_node)
print(a)
print(a.graph.edges)
输出:
a
:
{"name": "foobar","graph": {"nodes": [{"type": "l3out","position": {"x":0,"y":0},"parameters": {"application_name":{"name": "application_name","value": "foobar","is_required": true,"description": "Ime aplikacije"}}}, {"type": "tier","position": {"x":100,"y":100},"parameters": {"application_name":{"name": "application_name","value": "foobar","is_required": true,"description": "Ime aplikacije"},"tier_name":{"name": "tier_name","value": "bar","is_required": true,"description": "Ime nivoja"},"hypervisor":{"name": "hypervisor","value": "","is_required": true,"description": "Kateri hypervisor je pripet na ta nivo (vse virtualke na tem nivoju bodo narejene na tem hypervisorju"}}}, {"type": "tier","position": {"x":100,"y":-100},"parameters": {"application_name":{"name": "application_name","value": "foobar","is_required": true,"description": "Ime aplikacije"},"tier_name":{"name": "tier_name","value": "bar","is_required": true,"description": "Ime nivoja"},"hypervisor":{"name": "hypervisor","value": "","is_required": true,"description": "Kateri hypervisor je pripet na ta nivo (vse virtualke na tem nivoju bodo narejene na tem hypervisorju"}}}],"edges": [{"source": {"type": "l3out","position": {"x":0,"y":0},"parameters": {"application_name":{"name": "application_name","value": "foobar","is_required": true,"description": "Ime aplikacije"}}}, "destination": {"type": "tier","position": {"x":100,"y":100},"parameters": {"application_name":{"name": "application_name","value": "foobar","is_required": true,"description": "Ime aplikacije"},"tier_name":{"name": "tier_name","value": "bar","is_required": true,"description": "Ime nivoja"},"hypervisor":{"name": "hypervisor","value": "","is_required": true,"description": "Kateri hypervisor je pripet na ta nivo (vse virtualke na tem nivoju bodo narejene na tem hypervisorju"}}}}, {"source": {"type": "l3out","position": {"x":0,"y":0},"parameters": {"application_name":{"name": "application_name","value": "foobar","is_required": true,"description": "Ime aplikacije"}}}, "destination": {"type": "tier","position": {"x":100,"y":-100},"parameters": {"application_name":{"name": "application_name","value": "foobar","is_required": true,"description": "Ime aplikacije"},"tier_name":{"name": "tier_name","value": "bar","is_required": true,"description": "Ime nivoja"},"hypervisor":{"name": "hypervisor","value": "","is_required": true,"description": "Kateri hypervisor je pripet na ta nivo (vse virtualke na tem nivoju bodo narejene na tem hypervisorju"}}}}]}}
a.graph.edges
:
[{'source': {"type": "l3out","position": {"x":0,"y":0},"parameters": {"application_name":{"name": "application_name","value": "foobar","is_required": true,"description": "Ime aplikacije"}}}, 'destination': {"type": "tier","position": {"x":100,"y":100},"parameters": {"application_name":{"name": "application_name","value": "foobar","is_required": true,"description": "Ime aplikacije"},"tier_name":{"name": "tier_name","value": "bar","is_required": true,"description": "Ime nivoja"},"hypervisor":{"name": "hypervisor","value": "","is_required": true,"description": "Kateri hypervisor je pripet na ta nivo (vse virtualke na tem nivoju bodo narejene na tem hypervisorju"}}}}, {'source': {"type": "l3out","position": {"x":0,"y":0},"parameters": {"application_name":{"name": "application_name","value": "foobar","is_required": true,"description": "Ime aplikacije"}}}, 'destination': {"type": "tier","position": {"x":100,"y":-100},"parameters": {"application_name":{"name": "application_name","value": "foobar","is_required": true,"description": "Ime aplikacije"},"tier_name":{"name": "tier_name","value": "bar","is_required": true,"description": "Ime nivoja"},"hypervisor":{"name": "hypervisor","value": "","is_required": true,"description": "Kateri hypervisor je pripet na ta nivo (vse virtualke na tem nivoju bodo narejene na tem hypervisorju"}}}}]
问题的症结在于目标层应该是“ foo”和“ bar”,但在两种情况下都是“ bar”