jay
jay

Reputation: 33

I continue to get a key error when trying to access my dictionary

I am trying to print the weights of the graph vertices using the get_weight method.

When I try access it like this:

test.final.vert_dict[1].get_weight(Vertex(2)) 

I get "KeyError: 2"

But if I try to access the weights through a for loop:

for key in test.final.vert_dict[1].adjacent:
        print(test.final.vert_dict[1].get_weight(key)) 

I am able to get them, including the weight of key 2.
The types of 'key' and 'Vertex(2)' are the same. I am not sure why I get a key error when I access it one way but not when I access it another. Please help.

class Vertex:
  def __init__(self, node):
    self.id = node
    self.adjacent = {}

  def __str__(self):
    return str(self.id) + ' adjacent: ' + str([x.id for x in self.adjacent])

  def add_neighbor(self, neighbor, weight=0):
    # print("This is add_neighbor type"+str(type(neighbor)))
    self.adjacent[neighbor] = weight

  def get_connections(self):
    return self.adjacent.keys()  

  def get_id(self):
    return self.id

  def get_weight(self, neighbor):
    # print("This is get_weight type"+str(type(neighbor)))
    return self.adjacent[neighbor]



class Graph:
  def __init__(self):
    self.vert_dict = {}
    self.num_vertices = 0


  def add_vertex(self, node):
    self.num_vertices = self.num_vertices + 1
    new_vertex = Vertex(node)
    self.vert_dict[node] = new_vertex
    return new_vertex

  def get_vertex(self, n):
    if n in self.vert_dict:
        return self.vert_dict[n]
    else:
        return None

  def add_edge(self, frm, to, cost = 0):
    # if cost < 0:
    #   self.remove_edge(frm, to)
    #   return

    if frm not in self.vert_dict:
      self.add_vertex(frm)
    if to not in self.vert_dict:
      self.add_vertex(to)

    self.vert_dict[frm].add_neighbor(self.vert_dict[to], cost)
    self.vert_dict[to].add_neighbor(self.vert_dict[frm], cost)

  def get_vertices(self):
    return self.vert_dict.keys()



  # def remove_edge(self, frm, to):
  #     if frm or to not in self.vert_dict:
  #         return
  #     self.vert_dict[frm]
    

if __name__ == '__main__':
    
  test = MakeGraph()
  h = test.formatfile("topology.txt")
  test.buildgraph(h)

  # print(test.final.vert_dict[1].get_weight(Vertex(2)))


  for key in test.final.vert_dict[1].adjacent:
    print(test.final.vert_dict[1].get_weight(key))

Upvotes: 1

Views: 245

Answers (1)

cadolphs
cadolphs

Reputation: 9647

You are using instances of class Vertex as key. Since you have not implemented __hash__ and __eq__ for your class, it'll follow Python's default behavior for objects: The hash will be the actual instance's id and two vertices will only be considered equal if they're the same object.

Try this out to see:

one_vertex = Vertex(2)
another_vertex = Vertex(2)

are_they_the_same = one_vertex == another_vertex
print(are_they_the_same) # this will print false

So now whatever instance of Vertex you used while creating your graph, that will be totally different from the Vertex(2) that you create freshly. Since that's now a different vertex, it's not in your vert_dict, and that's why you get a key error.

Long story short what can you do about it?

You can rewrite your graph class so that your graph class looks up nodes by their node id instead of by their actual object.

You could also implement a different __hash__ and __eq__ for your Vertex class but in this case I think that's not a good idea because your vertices are mutable: You can add stuff (like neighbors) to them and then even if two instances of the Vertex class have the same id they shouldn't be considered equal.

Upvotes: 1

Related Questions