Reputation: 13
So I've been trying to work out this error for awhile now and I can't seem to figure out what the problem is. All I want is to have a dictionary with various keys that can be associated with multiple values. I keep getting this error:
Traceback (most recent call last):
File "C:/Users/.py", line 34, in insert_nodes
self.__graph_dict[value].append(node2)
AttributeError: 'Node' object has no attribute 'append'
It's entirely possible I'm overlooking something small or just really confused about how I should be approaching this issue. My code is as follows:
class Node(object):
def __init__(self, value, colored):
self.value = value
self.colored = colored
class Graph(object):
def __init__(self):
self.graph_dict = {}
def nodes(self):
return self.nodes.keys()
def insert_nodes(self, value, neighbor):
node1 = Node(value, colored="blank")
node2 = Node(neighbor, colored="blank")
if value in self.graph_dict:
self.graph_dict.setdefault(value, [])
self.graph_dict[value].append(node2)
else:
self.graph_dict[value] = node2
def populate_graph(self):
graph_name = input("Enter your graph name ")
f = open(graph_name, 'r').readlines()
num_vertices = f.pop(0)
for lines in f:
pairs = lines.split(" ")
self.insert_nodes(int(pairs[0]), int(pairs[1].rstrip()))
g = Graph()
g.populate_graph()
Any help would be appreciated.
Upvotes: 1
Views: 452
Reputation: 3644
You could take advantage of collections.defaultdict
as follows:
from collections import defaultdict
(...)
def __init__(self):
self.graph_dict = defaultdict(list)
(...)
def insert_nodes(self, value, neighbor):
node1 = Node(value, colored="blank")
node2 = Node(neighbor, colored="blank")
# no need for the if
self.graph_dict[value].append(node2)
Another option, and one of the correct ways to use the setdefault
in that scenario would be the following:
(...)
def insert_nodes(self, value, neighbor):
node1 = Node(value, colored="blank")
node2 = Node(neighbor, colored="blank")
self.graph_dict.setdefault(value, [])
self.graph_dict[value].append(node2)
although I don't prefer it, it is valid and readable, IMHO. I still find more appealing the defaultdict
approach.
Edit: Or, more or less equivalent but with less lookups:
(...)
def insert_nodes(self, value, neighbor):
node1 = Node(value, colored="blank")
node2 = Node(neighbor, colored="blank")
self.graph_dict.setdefault(value, []).append(node2)
"It is better to ask for forgiveness thant ask for permission"... or something like that. It is considered more pythonic, and it is indeed faster, to just try to do it and catch the exception.
This is more related to style, given that @barny has already fixed the bug. However, I include it for completeness:
(...)
def insert_nodes(self, value, neighbor):
node1 = Node(value, colored="blank")
node2 = Node(neighbor, colored="blank")
try:
self.graph_dict[value].append(node2)
catch KeyError:
self.graph_dict[value] = [node2]
Upvotes: 0
Reputation: 6826
Append() is expecting a list - so the dictionary content of graph_dict isn't a list. This is because when you initialise it you give it a value, not a list. Change:
if value in self.graph_dict:
self.graph_dict.setdefault(value, [])
self.graph_dict[value].append(node2)
else:
self.graph_dict[value] = node2
to:
if value in self.graph_dict:
## not needed self.graph_dict.setdefault(value, [])
self.graph_dict[value].append(node2)
else:
self.graph_dict[value] = [node2]
Upvotes: 2