I am new to python and trying to implement graph data structure in Python.
I have written this code, but i am not getting the desired result i want.
Code:
class NODE:
def __init__(self):
self.distance=0
self.colournode="White"
adjlist={}
def addno(A,B):
global adjlist
adjlist[A]=B
S=NODE()
R=NODE()
V=NODE()
W=NODE()
T=NODE()
X=NODE()
U=NODE()
Y=NODE()
addno(S,R)
for keys in adjlist:
print keys
I want the code to print {'S':R} on the final line but it is printing this:
<__main__.NODE instance at 0x00000000029E6888>
Can anybody guide me what am i doing wrong? Also what to do if i want to add another function call like addnode(S,E) and printing should be {S:[R,E]}
You node needs to have a label to print. You can't use just the variable name. The node has no way knowing name of your variable.
class NODE:
def __init__(self, name):
self.name=name
def __repr__(self):
return self.name
adjlist={}
def addno(A,B):
global adjlist
adjlist[A]=B
S=NODE('S')
R=NODE('R')
addno(S,R)
print adjlist
>>> {S: R}
However python dict may have only one value for each key, so you wont be able to save {S: R} and {S: V} at the same time. Instead you will need to save aj array of nodes:
class NODE:
def __init__(self, name):
self.name=name
def __repr__(self):
return self.name
adjlist={}
def addno(A,B):
global adjlist
if A not in adjlist:
adjlist[A] = []
adjlist[A].append(B)
S=NODE('S')
R=NODE('R')
V=NODE('V')
W=NODE('W')
addno(S,R)
addno(S,V)
addno(R,W)
print adjlist
{S: [R, V], R: [W]}
As a side note, using unnessesary global variables is a bad habit. Instead make a class for the graph:
class Node:
def __init__(self, name):
self.name=name
def __repr__(self):
return self.name
class Graph:
def __init__(self):
self.adjlist={}
def addno(self, a, b):
if a not in self.adjlist:
self.adjlist[a] = []
self.adjlist[a].append(b)
def __repr__(self):
return str(self.adjlist)
G=Graph()
S=Node('S')
R=Node('R')
V=Node('V')
W=Node('W')
G.addno(S,R)
G.addno(S,V)
G.addno(R,W)
print G
>>> {R: [W], S: [R, V]}
You get that output because Node is an instance of a class ( you get that hint form the output of your program itself see this: <main.NODE instance at 0x00000000029E6888> ).
i think you are trying to implement adjacency list for some graph algorithm. in those cases you will mostly need the color and ``distanceto othernodes`. which you can get by doing :
for keys in adjlist:
print keys.colournode , keys.distance
Related
I would like to store a number of temperature values as a dictionary instance attribute. Whenever the dictionary key is used, I would like the corresponding value to update, with behaviour similar to that of an instance #property decorator.
Is there a way to to this without updating the entire dictionary? Below is code of how I'd expect it to pan out, with simplified update functions (the real ones will read from sensors), but the temperatures need to update on each access.
import random
class Thermal():
def __init__(self):
self.temperatures = {'outside': self.outside, 'inside': self.inside}
#property
def outside(self):
return random.random()
#property
def inside(self):
return 1 + random.random()
#property
def c(self):
return random.random()
a = Thermal()
print(a.temperatures['outside'])
print(a.temperatures['outside'])
print(a.temperatures['inside'])
print(a.temperatures['inside'])
The outside and inside temperatures printed above do not change on access, though of course it works for the basic attribute, c. Is this a case where I need to create a dict subclass, or is there another way to do it?
I can resign to having individual instance attributes for each temperature, but I think it's neater in a dictionary and am keen to see if there is a way to achieve this.
With minimal changes to your code and keeping the semantics like a.temperatures['outside'] here is possible solution:
import random
class Temperatures(): # here
def __init__(self, thermal):
self.thermal = thermal
def __getitem__(self, item):
return getattr(self.thermal, item)
class Thermal():
def __init__(self):
self.temperatures = Temperatures(self) # and here
#property
def outside(self):
return random.random()
#property
def inside(self):
return 1 + random.random()
#property
def c(self):
return random.random()
a = Thermal()
print(a.temperatures['outside'])
print(a.temperatures['outside']) # will give different random number
print(a.temperatures['inside'])
print(a.temperatures['inside'])
How about this?
class Thermal:
def __init__(self):
self._temperatures = {'inside': None, 'outside': None}
def __getitem__(self, key):
self.update()
return self._temperatures[key]
def update(self):
# update temperatures here...
I have a list of class objects that I would like to distribute to other lists as objects and then these lists should be called to provide interaction with the objects within.
The issue that I cannot overcome at the moment is when trying to append the objects with a for loop from the first list to the second one and instead getting the new list populated with the class objects I get their pointers to the memory.
This is currently running on Python 3.x if any difference.
I have seen some cases where the suggestion is to play with __str__ and
__repr__ but I don't come to a solution for my case.
class Robot():
"""Test class"""
def __init__(self, age):
self.age = age
r = Robot(10)
r1 = Robot(15)
mylist1 = [r, r1]
mylist2=[]
for item in mylist1:
mylist2.append(item)
print(mylist2)
I would expect to get something like [r, r1]
This is the result I get instead:
[<__main__.Robot object at 0x000001285CEE33C8>, <__main__.Robot object at 0x000001285CEE3748>]
As pointed by others in comments.In your code at the moment you are getting the expected result as r and r1 are the instances of the class. In case you want to differentiate your instances on the basis of name and want to return the same you can pass name argument and define __repr__ to represent your output when str(instance) is being called. Just giving you a heads up:
class Robot():
"""Test class"""
def __init__(self, age, name):
self.age = age
self.name = name
def __repr__(self):
return self.name
r = Robot(10,'r')
r1 = Robot(15,'r1')
mylist1 = [r, r1]
mylist2 = []
for item in mylist1:
mylist2.append(item)
print(mylist2)
Result:
[r, r1]
Otherway could be to use a dictionary for mapping
class Robot():
"""Test class"""
def __init__(self, age,name):
self.age = age
self.name=name
r = Robot(10,'r')
r1 = Robot(15,'r1')
mylist1 = [r, r1]
d={}
for item in mylist1:
d[item.name]=item
print(d)
Output
{'r': <__main__.Robot instance at 0x0000000010BAD708>, 'r1': <__main__.Robot instance at 0x0000000010BAD148>}
Suppose I have a data structure composed of objects in Python like this:
class Planet:
def __init__(self, name):
self.name = name
self.continents = []
class Continent:
def __init__(self, name):
self.name = name
self.countries = []
class Country:
def __init__(self, name):
self.name = name
self.states = []
class State:
def __init__(self, name):
self.name = name
self.cities = []
class City:
def __init__(self, name):
self.name = name
Now suppose I was to create a function that would be able to take an object and an attribute "path" as parameters and output a list of all the objects that "match" that path. Since I don't really know how to describe very well what I'm thinking of and most likely I'm using the wrong terminology, here is an idea of what it might look like in practice (let's call the function collect, and assume that the data structure is populated with data, with planet being the "root" object of the data structure):
planet = Planet("Earth")
... Code for populating data structure ...
collect(planet, "continents.countries.states.cities")
This function call would return a list of every cities in every state in every country in every continent on the planet. Or if I wanted all the states in the data model I would do:
collect(planet, "continents.countries.states")
Hopefully you get the idea. The problem is that I just have no clue how I would accomplish this. Here's what I've come up with so far:
def collect(obj, attr_path):
attrs = attr_path.split(".")
current_attr = obj
items = []
for attr in attrs:
current_attr = getitem(current_attr, attr)
# Not sure what to do here...
return items
Does anyone know how I can make this work?
If you would like to do a breadth first search:
def bfs(queue, results):
try:
obj, attr_path = queue.pop(0)
except IndexError:
return
if attr_path is None:
results.append(obj)
else:
if '.' in attr_path:
first, rest = attr_path.split('.', maxsplit=1)
else:
first, rest = attr_path, None
children = getattr(obj, first)
for child in children:
queue.append((child, rest))
bfs(queue, results)
def collect(obj, attr_path):
queue = [(obj, attr_path)]
results = []
bfs(queue, results)
return results
Disclaimer: untested
Say I have a Graph class and a Vertex class, defined as below
Graph.py
class Graph:
def __init__(self):
self.adjacencyList = {}
def __str__(self):
return str(self.adjacencyList)
def addVetex(self,key,value):
if Vertex(key,value) not in self.adjacencyList:
self.adjacencyList[Vertex(key,value)] = []
Vertex.py
class Vertex:
def __init__(self,key,value):
self.key = key
self.value = value
def __str__(self):
return "Key: ",str(self.key)," Value: ",str(self,value)
def __hash__(self):
return self.key
if I do this:
G = Graph()
G.addVetex(1,None)
G.addVetex(2,None)
G.addVetex(1,3)
print G
It print out {<Vertex.Vertex instance at 0x110295b90>: [], <Vertex.Vertex instance at 0x110295bd8>: []} But I am expecting something like {"Key:1 Value:None":[]...}
My question is what I am doing wrong? When a diction got print out, why it does not try to call the str function of its keys/values?
Thanks.
I believe the method you want to implement to get the string you want with your current code is Vertex.__repr__, which is what the python dictionary uses to get string representations of keys.
Here's a related stackoverflow answer that sheds some light on the difference between __repr__ and __str__
Joe's answer is correct, here is the tested version of the code:
def __repr__(self):
return "Key: "+str(self.key)+" Value: "+str(self.value)
to be implemented in Vertex. Also important is that a string is given back, not a tuple as in the question.
This will do it. Note the addition of the repr method (and a little cleanup of the str method).
class Vertex:
def __init__(self,key,value):
self.key = key
self.value = value
def __str__(self):
return "{Key: "+str(self.key)+" Value: "+str(self.value)+"}"
def __hash__(self):
return self.key
def __repr__(self):
return str(self)
You might consider subclassing a dict, though, for your vertex class. You get all the benefits of a dict but can add methods to suit your needs. The simplest version of this would look like:
class Vertex(dict):
pass
You can do smth like:
class Graph(object):
def __str__(self):
return ", ".join("Key: " + str(i.key) + " Value: " + str(i.value) for i in self.adjacencyList)
the next is my code:
class a:
w={}
def __setattr__(self,name,value):
self.w[name]=value
def __getattr__(self,name):
return self.w[name]
b=a()
b.e='eee'
b['f']='fff'
print b.e,b['f'],b.w
#error
what is the difference between b.e and b['f'].
thanks
class MyClass(object):
def __init__(self):
self.w = {}
def __setitem__(self, k, v):
self.w[k] = v
def __getitem__(self, k):
return self.w[k]
mc = MyClass()
mc['aa'] = 12
print mc['aa']
setitem/getitem is for indexed access (with square brackets) like shown above. setattr/getattr is for attribute access (i.e. mc.aa)
__ set/getitem__() are used for indexing. Define them as well.
You have not defined any method/attribute called self.e
If instead, you were to say self.w[e] = 'eee', then you're errors should disappear.