Python 字典更改一个值(列表)更改所有值(列表),deepcopy 无法解决问题

时间:2021-06-04 10:45:23

标签: python python-3.x dictionary

我创建了一个将列表作为值保存的字典,当我更改这些值之一时,字典中的所有值最终都会更改。我认为这将是一个经典的指向问题,但是,deepcopy 没有帮助。另外,我相信硬编码作业总是会在内存中创建新项目。

字典的创建简化(deepcopy也可以去掉,达到同样的效果):

self.connections= {}
self.connections['20000']= copy.deepcopy([None, None, []])
self.connections['20001']= copy.deepcopy([None, None, []])

创建后,我们稍后更改这样的值:

if self.nodes[ip1].connections[port1][0]==None and self.nodes[ip2].connections[port2][0]==None:
            self.nodes[ip1].connections[port1]= copy.deepcopy([ip2, port2, []])
            self.nodes[ip2].connections[port2]= copy.deepcopy([ip1, port1, []])

当逐步执行如下完整代码时,我可以看到对一个键值的个别更改会更改所有值。该代码用于模拟集群,供我试验一些分布式控制算法。

sim.py

#~ Info
__doc__ = 'Creates a simulation of a running cluster'

#~ Imports
from node import Node

import threading
import pygame
import math
import copy


#~ Sim
class Sim:
    
    nodes= {}
    mutex = threading.Lock()
    screen= pygame.display.set_mode((500, 500))
    clock= pygame.time.Clock()

    def __init__(self):
        # Init nodes
        for i in range(3):
            self.nodes['192.168.0.{}'.format(i)]= Node(self, '192.168.0.{}'.format(i))


    def run(self):
        # Run nodes in diffrent threads
        # for k,d in self.nodes.items():
        #     t= threading.Thread(target=Node.run, args=(d,))
        #     t.setDaemon= True
        #     t.start()

        for k,d in self.nodes.items():
            d.run()

        # Drawing
        diff_angle= 2*math.pi/len(self.nodes.keys())
        s_colour= (255, 255, 0)
        e_colour= (255, 255, 255)

        n_colour= (0, 0, 255)

        def rotate(angle):
            s = math.sin(angle)
            c = math.cos(angle)
            return (250 + 150*c - 0*s, 250 + 150*s + 0*c)

        while True:
            self.screen.fill((0,0,0))

            # Draw connections
            for k,d in self.nodes.items():
                for selport,(tarip, tarport, buffer) in d.connections.items():

                    if tarip!=None and tarport!=None:
                        start= int(k.split('.')[-1])
                        end= int(tarip[0].split('.')[-1])

                        if tarport=='20000' or tarport=='20001':
                            pygame.draw.line(self.screen, s_colour, rotate(start*diff_angle), rotate(end*diff_angle), 4)
                        else:
                            pygame.draw.line(self.screen, e_colour, rotate(start*diff_angle), rotate(end*diff_angle), 4)

            # Draw nodes
            for k,d in self.nodes.items():
                ind= int(k.split('.')[-1])
                pygame.draw.circle(self.screen, n_colour, rotate(ind*diff_angle), 20)

            pygame.display.update()
            self.clock.tick(60)

            for k,d in self.nodes.items():
                print(d)

            print()

 
    def connect_node_to_node(self, ip1, port1, ip2, port2):
    
        self.mutex.acquire(blocking=True)

        # Check both ports are clear then connect them
        try:
            if self.nodes[ip1].connections[port1][0]==None and self.nodes[ip2].connections[port2][0]==None:
                self.nodes[ip1].connections[port1]= copy.deepcopy([ip2, port2, []])
                self.nodes[ip2].connections[port2]= copy.deepcopy([ip1, port1, []])
                self.mutex.release()
                return True

        # If either port doesn't exist
        except KeyError:
            pass

        self.mutex.release()
        return False

        

        




if __name__=='__main__':
    pygame.init()
    sim= Sim()
    sim.run()

节点.py

#~ Info
__doc__ = 'Holds the class for simulated nodes'

#~ Imports
import copy


#~ Node
class Node:

    # <sel port> : [<tar ip>, <tar port>, []]
    connections= {}

    def __init__(self, network, ip):
        self.network= network
        self.ip= ip
        self.connections['20000']= copy.deepcopy([None, None, []])


    def __str__(self):
        line= 'Node {}: ['.format(self.ip)

        for selport,(tarip, tarport, buffer) in self.connections.items():

            if tarip!=None and tarport!=None:
                line+= '{}-{}:{},'.format(selport, tarip, tarport)
            else:
                line+= 'Listening'

        return line+']'
    

    def run(self):

        self.connections['20001']= copy.deepcopy([None, None, []])
        
        # while True:
        for i in range(3):
            
            if self.network.connect_node_to_node(self.ip, '20001', '192.168.0.0', '20000'):
                return True

0 个答案:

没有答案