How do you use dictionary in class? - python

I have to put name and student_num in dictionary.
the thing is I don't know how to call dictionary in class? how can i put name and student_num in that format?
class Cool():
def __init__(self, name, student_num, new_dict):
self._key = name
self._value = student_num
self._new_dict = new_dict
def get_name(self):
return self._key
def get_student_number(self):
return self._value
def new_dict(self):
return self._new_dict
# I want to put name and student_name in this format:
# {'name': 'student name'}
def get_dict(self, new_dict):
self._new_dict = {}
self._new_dict[self._key] = self._value
return self._new_dict[self._key]
def __str__(self):
return str(self._new_dict[self._key])
Now when I test this code
>>>a = Cool({}, 'diana', 1234)
>>>print(a)
I get the following error:
File "C:\Program Files (x86)\Wing IDE 101 5.0\src\debug\tserver_sandbox.py", line 20, in str
builtins.TypeError: 'int' object is not subscriptable

You are calling cool incorrectly.
Try:
>>>a = Cool('diana', 1234, {})
Some more suggestions:
class Cool():
def __init__(self, name, student_num, new_dict):
self._key = name
self._value = student_num
self._new_dict = new_dict
def get_name(self):
return self._key
def get_student_number(self):
return self._value
def get_dict(self):
self._new_dict[self._key] = self._value
return self._new_dict[self._key]
def __str__(self):
return str(self._new_dict[self._key])
In order to get print to work (the way the code is currently). You need to first call get_dict.
You could just do the following:
a = Cool('diana', 1234, {})
print(a.get_dict())
or you could edit your code to handle the dict earlier.

To your edited question,
>>>a = Cool({}, 'diana', 1234)
does this:
class Cool():
def __init__(self, name, student_num, new_dict):
self._key = name # name is {}
self._value = student_num # student_num is 'diana'
self._new_dict = new_dict # new_dict is 1234
Then
>>print(a)
does this:
def __str__(self):
return str(self._new_dict[self._key])
=> _new_dict is 1234
=> return 1234[self._key]
=> self._key is {}
=> return 1234[{}]
=> TypeError: 'int' object is not subscriptable
something[] is a subscript, a slice, operation, and Python can't do that with numbers.
It's not clear to me what the whole code should do, but it looks like several times more code than it needs to be. I assume some of this is mandated by the assignment requirements?
Are you creating one "Cool" class per student? Or one "Cool" class for many students? It looks at the moment like that's not certain - if it's one Cool class per student, putting one name in a dictionary and taking it out again doesn't add anything to the class. If it's one Cool class for a lot of students, then get_name makes no sense because there will be many names and get_student_number will need a way to identify which student.

Related

Dictionary keys not present though they are being added

This is my code :
class member:
def __init__(self, name):
self.name = name
def get_name(self, name):
self.name = name
def __str__(self):
return self.name
class create_graph:
def __init__(self):
self.some_dict = dict()
def add(self, name):
if name is None:
raise TypeError
print(name not in self.some_dict)
if name not in self.some_dict:
self.some_dict[name] = []
else:
print(str(name) + "is already present")
def link(self, p1, p2):
if p1 in self.some_dict:
self.some_dict[p1].append(p2)
else:
self.some_dict[p1] = [p2]
some_graph = create_graph()
list_person = ['abc', 'xyz', 'mno', 'pqr']
for person in list_person:
some_graph.add(member(person))
print(len(some_graph.some_dict))
for i in range(len(list_person)-1):
some_graph.link(i,i+1)
print(len(some_graph.some_dict))
I am not able to find the error in this code.
When the add function is called, I get the True message indicating it is added. The first print statement prints that the number of keys are 4 but after adding the links, it says the keys are 7.
I want to have just 4 even after adding the link.
Thanks for the help !
Print out the dictionary in question.
print(some_graph.some_dict)
produces
{<__main__.member object at 0x7fe8326abe80>: [], <__main__.member object at 0x7fe8326abeb8>: [], <__main__.member object at 0x7fe8326abe48>: [], <__main__.member object at 0x7fe8326abef0>: []}
The keys of this dictionary are instances of the class member, not the strings in the list list_person.
I you did:
persons_in_graph_dict = {k.name for k in some_graph.some_dict}
for person in list_person:
print(person)
print(person in persons_in_graph_dict)
print()
You would get:
abc
True
xyz
True
mno
True
pqr
True
You can fix the problem by adding a __contains__() method to your CreateGraph class that expects a string argument called name. How to do this and then use it shown in the code below.
Note: I have changed all your class names to the CapitalizedWords-style to conform to the PEP8 coding guidelines (in its Naming Conventions section).
class Member:
def __init__(self, name):
self.name = name
def get_name(self, name):
self.name = name
def __str__(self):
return self.name
class CreateGraph:
def __init__(self):
self.some_dict = dict()
def add(self, name):
if name is None:
raise TypeError
if name not in self.some_dict:
self.some_dict[name] = Member(name)
else:
print("{} is already present".format(name))
def __contains__(self, name): # <-- METHOD ADDED.
return name in self.some_dict
some_graph = CreateGraph()
list_person = ['abc', 'xyz', 'mno', 'pqr']
for person in list_person:
some_graph.add(person)
print("checking these names in list_person:", list_person)
for person in list_person:
if person in some_graph:
print("Present")
else:
print("Not present")
Here's the output:
checking these names in list_person: ['abc', 'xyz', 'mno', 'pqr']
Present
Present
Present
Present
You are storing instances as key. call name()to get the name
try testing like below
for i in some_graph.some_dict:
print ((i.name) in list_person)

Recursive listing of all objects at an arbitrary depth in a data model?

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

converting a subclass with __slots__ to json

I am a total noob in Python and just couldn't help myself but did it again and dreamed of something I just couldn't achieve.
I wanted to have a class, which can be instantiated as such:
my_class = MyClass(**params)
and be consumed as such, in Flask:
jsonify(my_class)
The expected outcome would be a JSON:
{ "key" : "value", ... }
Now, the implementation of MyClass is,
class MyClas(NamedMutableSequence, Document):
__slots__ = (
'key_1',
'key_2',
'key_3'
)
def __init__(self, **params):
NamedMutableSequence.__init__(self, **params)
Document.__init__(self, 'myclass')
def save(self):
self._db_col.update({'key_1': self.key_1}, {'key_2': self.key_2, 'key_3': self.key_3})
By now, you are wondering what NamedMutableSequence and Document are...
class NamedMutableSequence(Sequence):
___slots__ = ()
def __init__(self, *positional_values, **keyword_values):
subclass_propeties = self.__slots__
for key in subclass_propeties:
setattr(self, key, keyword_values.get(key))
if positional_values:
for key, value in zip(subclass_propeties, positional_values):
setattr(self, key, value)
def __str__(self):
values = ', '.join('%s=%r' % (key, getattr(self, key)) for key in self.__slots__)
return '%s(%s)' % (clsname, values)
__repr__ = __str__
def __getitem__(self, item):
return getattr(self, item)
def __setitem__(self, item, value):
return setattr(self, item, value)
def __len__(self):
return len(self.__slots__)
Admittedly, I just copied someone's solution to a mutable namedtuple for this base class and fixed __getitem__ & __setitem__ to allow my_class.key_1 = 'some value'
class Document():
__slots__ = ('_db_col')
def __init__(self, collection):
self._db_col = mongo_db[collection]
This is just what I spew out in attempt for a base class which I will be using throughout my model classes for db connection.
This is, in my opinion, where it starts I got too over myself and just created a mess. Because no matter what I try, I can't stop raising TypeError: {string value of my_class} is not JSON serializable.
To make matters worse, when I try to dict(my_class), I get a shiny attributes must be string error raised on getattr().
I would still like to keep the base classes and I still need to make it JSON serializable.
How can I save myself?
I found an answer finally, and the solution was found from another stackoverflow post (How can I convert python class with slots to dictionary?)
What I did was just to add another method on the NamedMutableSequence as such:
def json(self):
return {key : getattr(self, key, None) for key in self.__slots__}
and just call it when I need a JSON parsable dictionary, as such:
my_class = MyClass(**params)
jsonify(my_class.json())

create python factory method

I have the following simple example:
class CatZoo(object):
def __init__(self):
raise NotImplemented
#classmethod
def make_zoo_cat(cls, name, age, gender, location):
cls._names = name
cls._ages = age
cls._genders = gender
cls._location = location
return cls
#classmethod
def make_zoo_cats(cls, names, ages, genders, location):
cls._names = names
cls._ages = ages
cls._genders = genders
cls._location = location
return cls
#property
def location(self):
return self._location
#property
def names(self):
return self._names
def age(self, name):
if name in self._names:
return self._ages[self._names.index(name)]
else:
return None
def gender(self, name):
if name in self._names:
return self._genders[self._names.index(name)]
else:
return None
#property
def meow(self):
return "meow!"
And I am trying to create an object of this class by using the following:
cat_zoo = CatZoo.make_zoo_cat('squeakers', 12, 'M', 'KC')
print "The name is {}".format(cat_zoo.names)
This is just an example, I am just trying to make my factory methods work (make_zoo_cat, make_zoo_cats). The first will be passed one name, age, gender and location where the second would be passed a list of names, ages and genders and one location. If I run this code, I get the following output:
The name is <property object at 0x7fe313b02838>
Thanks,
Remove the NotImplemented initializer and actually create instances of your class, instead of mutating the class itself:
class CatZoo(object):
def __init__(self, name, age, gender, location):
self._names = name
self._ages = age
self._genders = gender
self._location = location
#classmethod
def make_zoo_cat(cls, name, ages, genders, location):
return cls.mak_zoo_cats([name], age, gender, location)
#classmethod
def make_zoo_cats(cls, names, ages, genders, location):
return CatZoo(names, age, gender, location)
#property
def location(self):
return self._location
#property
def names(self):
return self._names
def age(self, name):
if name in self._names:
return self._ages[self._names.index(name)]
else:
return None
def gender(self, name):
if name in self._names:
return self._genders[self._names.index(name)]
else:
return None
#property
def meow(self):
return "meow!"
Note that there was no real difference other than the method name between make_zoo_cat and make_zoo_cats, the difference in argument names doesn't change the functionality here.
Instead, I presumed that ._names should always be a list and that make_zoo_cat (singular) should create a CatZoo with one cat name in it.
Just remember that Python is not Java; you really don't need all those property objects, not where you could just access the attribute directly.
You didn't create any object in your code.
In your make_zoo_cats you return cls, so you still have a class not an instance of this class.
This code will print the yes
if CatZoo.make_zoo_cat('squeakers', 12, 'M', 'KC') == CatZoo:
print 'yes'
You agree than you can't do that, since name its a property it will only exist if you have an instance of that class.
CatZoo.names
to be able to use the property you need on instance of that class
something like that (this will raise in your code):
cat = CatZoo()
cat.names # I can do this now
An other point in your make_zoo_cat you create Class variables, those variables are accessible from the class (no need to have an instance on that class) but are "common" to all.
c1 = CatZoo.make_zoo_cat('squeakers', 12, 'M', 'KC')
print c1._names
print c1._ages
print c1._genders
print c1._location
print '*'*10
print CatZoo._names
print CatZoo._ages
print CatZoo._genders
print CatZoo._location
print '*'*10
c2 = CatZoo.make_zoo_cat('other', 42, 'F', 'FR')
print c2._names
print c2._ages
print c2._genders
print c2._location
print '*'*10
print CatZoo._names
print CatZoo._ages
print CatZoo._genders
print CatZoo._location
print '*'*10
print c1._names
print c1._ages
print c1._genders
print c1._location
the result will be someting like that:
squeakers
12
M
KC
**********
squeakers
12
M
KC
**********
other
42
F
FR
**********
other
42
F
FR
**********
other
42
F
FR
The first two give me the same result, and the last three as well, this is because they are class variables and you always have the same class so modifying one of those variable will affect the other

Python:How to print object key in a dictionary properly?

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)

Categories

Resources