World! I've encountered an unexpected behavior from my python interpreter during a project. I'm aware that, in certain situations, python uses the reference to an object, not the object itself. (for example: here) However, I cannot explain why this problem arises in this piece of code since the elements of the list seem to be different instances with different object ids. Whenever I add a new {key:value} pair to the dictionary, all other dictionaries in that list get updated.
class Node():
def __init__(self, name, neighbors=dict()):
self.name = name
self.neighbors = neighbors # a dict containing all neighboring nodes in form of {'name':value} pairs
def add_neighbor(self, neighbor, value=0):
self.neighbors[str(neighbor)] = value
if __name__ == "__main__":
n_1 = Node(name='node_1')
n_1.add_neighbor('node_2', value=5)
n_2 = Node(name='node_2')
node_list = [n_1, n_2]
for node in node_list:
print(id(node), node.name, node.neighbors)
output:
2129022374520 node_1 {'node_2': 5}
2129022374576 node_2 {'node_2': 5}
CodePudding user response:
class Node():
def __init__(self, name, neighbors=dict()):
This code is being executed when the class is parsed/interpreted. In particular, the default value for neighbors
is a single dictionary that is shared across class instances. A typical pattern for what you're trying to do is to instead write:
class Node():
def __init__(self, name, neighbors=None):
neighbors = neighbors or dict()
CodePudding user response:
A really interesting question actually...
This is because the same dict()
is assigned to both (in fact all instances of the object). If it was removed (for example replaced with a type hint) then this would work and you can do the dict allocation in the code.
So this would work:
class Node():
def __init__(self, name, neighbors:dict): # <--- change to a type hint
self.name = name
self.neighbors = neighbors # a dict containing all neighboring nodes in form of {'name':value} pairs
def add_neighbor(self, neighbor, value=0):
self.neighbors[str(neighbor)] = value
if __name__ == "__main__":
n_1 = Node(name='node_1', neighbors={}) # <-- dict is here
n_1.add_neighbor('node_2', value=5)
n_2 = Node(name='node_2', neighbors={}) # <-- a different dict is here
node_list = [n_1, n_2]
for node in node_list:
print(id(node), node.name, node.neighbors)
And this is the result:
2716705976384 node_1 {'node_2': 5}
2716712272224 node_2 {}