0

I have created a dict which holds lists as values, when I change one of these values all values in the dict end up changing. I thought it would be a classic pointing issue, however, deepcopy didn't help. Plus I believed that hardcoded assignments always created new items in memory.

The creation of the dictionary simplified (deepcopy can also be removed and achieve same results):

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

After creation we later change a value like this:

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, []])

When stepping through the full code as below, I can see that the individual change to one key value changes all values. The code is for a simulated cluster for me to experiment with some distributed control algorithms.

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()

node.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 Answers0