Building on Ben Rudgers answer above, I would change some small things. Storing the edge as string seems odd, so I changed it to a namedtuple. Naming the internal variables to something more readable. Raising an error on adding an edge with unknown nodes, instead of ignoring it.
I also added the directly_connected() and connected() methods the OP is asking for.
from collections import namedtuple
Edge = namedtuple('Edge', ['node_1', 'node_2'])
class Graph:
edges = set()
nodes = set()
def add_node(self, node):
self.nodes.add(node)
def remove_node(self, node):
self.nodes.remove(node)
def add_edge(self, node_1, node_2):
if self.exists_node(node_1) and self.exists_node(node_2):
self.edges.add(Edge(node_1, node_2))
else:
msg = 'Either {} or {} are not registered nodes!'
msg = msg.format(node_1, node_2)
raise KeyError(msg)
def remove_edge(self, node_1, node_2):
self.edges.remove(Edge(node_1, node_2))
def exists_edge(self, node_1, node_2):
return Edge(node_1, node_2) in self.edges
def exists_node(self, node):
return node in self.nodes
def directly_connected(self, node_1, node_2):
return self.exists_edge(node_1, node_2,)
def connected(self, node_1, node_2):
if self.directly_connected(node_1, node_2):
return True
for edge in self.edges:
if edge.node_1 == node_1:
return self.connected(edge.node_2, node_2)
return False
g = Graph()
g.add_node('A')
g.add_node('B')
g.add_node('C')
g.add_edge('A', 'B')
g.add_edge('B', 'C')
print("A -> C Directly connected: ", g.directly_connected('A', 'C'))
print("A -> C Connected: ", g.connected('A', 'C'))
Returns
A -> C Directly connected: False
A -> C Connected: True