我创建了一个将列表作为值保存的字典,当我更改这些值之一时,字典中的所有值最终都会更改。我认为这将是一个经典的指向问题,但是,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