从for循环分配字典键

时间:2019-07-03 08:55:44

标签: python dictionary reference mutable

我正在尝试按照以下说明创建有向图: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_idarguments_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”

0 个答案:

没有答案