I am a python newbie. I want display actual names,values and calories instead of [<__main__.Food object at 0x1097ba828>, <__main__.Food object at 0x1097ba860>, <__main__.Food object at 0x1097ba898>] I know this question is very simple,but it would be a great help if you could let me know the answer!
class Food(object):
def __init__(self,n,v,w):
self.name = n
self.value = v
self.calories = w
def getValue(self):
return self.value
def getCal(self):
return self.calories
def density(self):
return self.getValue()/self.getCal()
def __str__(self):
return '<__main__.Food: '+self.name +' '+ self.value+' ' + self.calories
def buildMenu(self):
menu = []
for i in range(len(values)):
menu.append(Food(self.name[i], self.value[i], self.calories[i]))
return menu
names=['burger','fries','coke']
values=[1,2,3]
calories=[100,200,300]
if __name__ == '__main__':
new = Food(names, values, calories)
print(new.buildMenu())
Thank you!
I made two code changes to get what I think you're looking for. The first is to convert values to strings in your str function. The second is to use that.
def __str__(self):
return '<__main__.Food: '+ str(self.name) +' '+ str(self.value)+' ' + str(self.calories)
and
print (str(new)) #instead of print(new.buildMenu())
Now the output is:
<main.Food: ['burger', 'fries', 'coke'] [1, 2, 3] [100, 200, 300]
This is how I would do it, noting that we've created two classes: a separate Food and Menu class. The Menu class has an add method that appends to its foodItems property, though I don't feel like that's really necessary since we can just do direct property assignment:
m.foodItems = < some list of Food objects >
I've removed the confusing buildMenu method from the Food class, and defined __str__ methods for both classes:
class Food(object):
def __init__(self,n,v,w):
self.name = n
self.value = v
self.calories = w
def getValue(self):
return self.value
def getCal(self):
return self.calories
def density(self):
return self.getValue()/self.getCal()
def __str__(self):
return '\t'.join([self.name, str(self.value), str(self.calories)])
class Menu(object):
def __init__(self):
self.foodItems = []
def add(self, foodItem):
self.foodItems.append(foodItem)
def __str__(self):
"""
prints the food items
"""
s = 'Item\tValue\tCalories\n'
s += '\n'.join(str(f) for f in self.foodItems)
return s
names=['burger','fries','coke']
values=[1,2,3]
calories=[100,200,300]
m = Menu()
items = list(Food(n,v,c) for n,v,c in zip(names,values,calories))
m.foodItems = items
print(m)
And outputs like:
The issue you have is that you're printing a list of Food instances, not a single instance at a time. The list type's __str__ operator calls repr on the items the list contains, not str, so your __str__ method does not get run.
A simple fix is to just rename your __str__ method to __repr__.
I'd note that it's a bit strange that you're building a Food instance with lists of values for name, value and calories, just so that you can call a method on it to make a list of Food instances with the individual values. A more Pythoic approach would be to pass the lists to a classmethod that returns the list of instances, without the intermediate instance needing to exist:
#classmethod
def buildMenu(cls, names, values, calories):
menu = []
for i in range(len(values)): # consider using zip instead of looping over indexes
menu.append(cls(names[i], values[i], calories[i]))
return menu
You'd call it on the class:
if __name__ == '__main__':
print(Food.buildMenu(names, values, calories))
Related
My __repr__ method works fine using objects created in it's class, but with objects that were created with the help of importing a library and using methods from it, it only represented the memory address...
from roster import student_roster #I only got the list if students from here
import itertools as it
class ClassroomOrganizer:
def __init__(self):
self.sorted_names = self._sort_alphabetically(student_roster)
def __repr__(self):
return f'{self.get_combinations(2)}'
def __iter__(self):
self.c = 0
return self
def __next__(self):
if self.c < len(self.sorted_names):
x = self.sorted_names[self.c]
self.c += 1
return x
else:
raise StopIteration
def _sort_alphabetically(self,students):
names = []
for student_info in students:
name = student_info['name']
names.append(name)
return sorted(`your text`names)
def get_students_with_subject(self, subject):
selected_students = []
for student in student_roster:
if student['favorite_subject'] == subject:
selected_students.append((student['name'], subject))
return selected_students
def get_combinations(self, r):
return it.combinations(self.sorted_names, r)
a = ClassroomOrganizer()
# for i in a:
# print(i)
print(repr(a))
I tried displaying objects that don't rely on anther library, and they dispayed properly.
The issue I was facing was linked to me not understanding the nature of the object. itertools.combinations is an iterable, and in order to represent the values stored I needed to either:
unpack it inside a variable like:
def get_combinations(self, r):
*res, = it.combinations(self.sorted_names, r)
return res
Iter through it inside a loop and leave the original code intact like
for i in a.get_combinations(2):
print(i)
I prefer the second solution
I am trying to make a class that includes the ability to display the length of a list. However, I get the message 'List has 0 items' instead of the actual number.
Here is my code:
'''
grocery_list = []
class GroceryList:
grocery_list = []
def __init__(self):
print('Grocery List Created')
def add(self, item):
self.grocery_list.append(item)
def show(self):
print(self.grocery_list)
def size(self):
print('List has {} items'.format(len(grocery_list)))
gro_list = GroceryList()
gro_list.add('Banana')
gro_list.add('Cat Food')
gro_list.show()
gro_list.size()
'''
Any help is appreciated.
In your question the indentation was messed up, however the problem was in method size(self) with grocery_list used instead of self.grocery_list.
Everything else works OK.
class GroceryList:
# declare grocery_list
grocery_list = []
def __init__(self):
print('Grocery List Created')
def add(self, item):
self.grocery_list.append(item)
def show(self):
print(self.grocery_list)
def size(self):
# self.grocery_list was the error
print('List has {} items'.format(len(self.grocery_list)))
if __name__ == "__main__":
gro_list = GroceryList()
gro_list.add('Banana')
gro_list.add('Cat Food')
gro_list.show()
gro_list.size()
You have two grocery_list in your code. One is a global one and the other is a class variable.
By len(grocery_list) You are finding the length of the grocery_list that is declared before the Class (global). Since you're not adding to that list (see your add() function), it shows you 0 items.
It should be len(self.grocery_list) - means find the length of grocery_list (class variable). See the self before the variable name.
class GroceryList:
grocery_list = []
def __init__(self):
print('Grocery List Created')
def add(self, item):
self.grocery_list.append(item)
def show(self):
print(self.grocery_list)
def size(self):
print('List has {} items'.format(len(self.grocery_list)))
gro_list = GroceryList()
gro_list.add('Banana')
gro_list.add('Cat Food')
gro_list.show()
gro_list.size()
Grocery List Created
['Banana', 'Cat Food']
List has 2 items
The reason you get zero in your code is that you are appending to the list (grocery_list) which is an attribute of the class. But in the size() function you are printing the length of the global grocery_list in which no elements were appended (i.e it is an empty list) so you get length as '0'
Try changing your size() function to this -
def size(self):
print('List has {} items'.format(len(self.grocery_list)))
Also, you can remove the grocery_list variable at the global level (first line), because it is useless in this code.
I have two classes (Student and Course). I'm trying to write a method for the Course class that will remove a given student from a course. However, there's a problem when I run
self.students.remove(student) in the method. The error tells me that student is not in the students list. Printing the students list I don't actually see the values, but instead I see a reference to it:
print(self.students)
> [<data.Student object at 0x7fc9980334f0>, <data.Student object at 0x7fc998033580>, <data.Student object at 0x7fc9980428b0>, <data.Student object at 0x7fc998042a00>]
However, if I select a specific student at an index then I'm able to see the actual data.
print(self.students[0])
> 2020411:King,Maha
Why is this happening when trying to print the students attribute?
Code if needed:
from copy import deepcopy
class Student:
def __init__(self, sid, last, first):
self.sid = sid
self.last = last
self.first = first
def __str__(self):
return '{}:{},{}'.format(self.sid, self.last, self.first)
def __repr__(self):
return '{}:{},{}'.format(self.sid, self.last, self.first)
class Course:
def __init__(self, crn, students):
self.crn = crn
self.students = deepcopy(students)
def key(self):
return self.crn
def is_empty(self):
return len(self.students) == 0
def get_student(self, student_key):
for student in self.students:
if student.key() == student_key:
return deepcopy(student)
return None
def __contains__(self, student):
for i in self.students:
if student.key() == i.key():
return True
break
return False
def register(self, student):
if student not in self:
self.students.append(deepcopy(student))
return
def drop(self, student):
s = None
if student in self:
s = deepcopy(student)
self.students.remove(student)
return s
student1 = Student(2020411, 'King', 'Maha')
student2 = Student(2019399, 'Hess', 'Alvin')
student3 = Student(2020301, 'Chin', 'Yu')
student4 = Student(2019111, 'Hay', 'Ria')
student_list = [student1, student2, student3]
course1 = Course('CP104', student_list)
removed_student = course1.drop(student2)
The issue with deepcopy() is that it creates an entirely new object that has the same attributes as the original one, yet they are not equal. For list.remove(), this compares the reference to check if the actual object exists. In your case, you are trying to remove an object that is not in the list.
Instead of removing it, if you want to return the student, use list.pop().
def drop(self, student):
for i, s in enumerate(self.students):
if s.sid == student.sid :
return self.students.pop(i)
As a side note, it will be easier to do operations if Course.students is a dictionary such that:
self.students = {
`sid1`: student1,
`sid2`: student2,
# etc
}
EDIT: Alternatively, implement __eq__() in Student so that list.remove() will work.
def __eq__(self, other):
return self.sid == other.sid and self.first == other.first and self.last == other.last
Im having trouble with this fifo-queue program, i've worked out most of the code, which looks like this:
class fifoQueue:
__L = []
def __init__(self):
self.__L = []
def __len__(self):
return len(self.__L)
def empty(self):
if len(q) == 0:
return True
else:
return False
def enqueue(self, e):
self.__L.insert(0, e)
return self.__L
def dequeue(self):
if self.empty():
self.__L = [e]
else:
return self.__L.pop()
def __str__(self):
return "'" + str(self.__L) + "'"
the problem I have is with the __ str __(self) function, what I want it to do is to return my list self.__L with "'" if I call print(str(q)), but if I only call print(q) I want it to return the list. Right now I get the same output for both print(q) and print(str(q)).
(print(str(q)) returns '[31.0]'
print(q) returns '[31.0]'
whereas I would like it to return
str(q) returns '[31.0]' or print(str(q)) returns '[31.0]'
print(q) returns [31.0]
I come from a background in mathematics and this is one of the first languages im learning so I apologize if this is very basic.
This is an assignment where I have to only use __ str __ to accomplish this, no additional functions can be created.
Any directions are greatly appreciated.
The __str__ method should be as follows:
def __str__(self):
return str(self.__L) # delegate to built-in function (no concatenation with quote)
Or:
def __str__(self):
return '{self.__L !s}'.format(self.__L) # string formatting
I've read more posts and documentation on __str__ and __repr__ than is healthy, consulted various texts, and still cannot resolve this printing issue, so I'm putting this out there.
Below is a function I'd like to test. The code isn't mine, but I would like to know how exactly it works. I need to see a human-friendly printout of the results (i.e., no hex), so that I can play with it and generally, well, learn something because I truly have no clue how it's doing what it's doing.
def get_ordered_adoption_center_list(adopter, list_of_adoption_centers):
"""
The method returns a list of an organized adoption_center such that the scores for each AdoptionCenter to the Adopter will be ordered from highest score to lowest score.
"""
list_of_adoption_centers.sort(key=lambda center:center.name)
list_of_adoption_centers.sort(key=lambda center:adopter.get_score(center), reverse=True)
return list_of_adoption_centers
Below is a relevant cross-section of code that it draws upon, which I did write.
import random
import string
class AdoptionCenter:
"""
The AdoptionCenter class stores the important information that a
client would need to know about, such as the different numbers of
species stored, the location, and the name. It also has a method to adopt a pet.
"""
def __init__(self, name, species_types, location):
self.name = name
self.species_types = species_types
self.location = (float(location[0]), float(location[1]))
def get_number_of_species(self, species):
return self.species_types.get(species, 0)
def get_location(self):
return self.location
def get_species_count(self):
return self.species_types.copy()
def get_name(self):
return self.name
def adopt_pet(self, species):
self.species_types[species] = self.species_types[species] - 1
if self.species_types[species] <= 0:
del self.species_types[species]
def __str__(self):
return "%s" % (self.name)
class Adopter:
"""
Adopters represent people interested in adopting a species.
They have a desired species type that they want, and their score is
simply the number of species that the shelter has of that species.
"""
def __init__(self, name, desired_species):
self.name = name
self.desired_species = desired_species
def get_name(self):
return self.name
def get_desired_species(self):
return self.desired_species
def get_score(self, adoption_center):
num_desired = adoption_center.get_number_of_species(self.desired_species)
score = float(1 * num_desired)
return score
def __str__(self):
return "%s and score is %d" % (self.name, self.get_score)
class FlexibleAdopter(Adopter):
"""
A FlexibleAdopter still has one type of species that they desire,
but they are also alright with considering other types of species.
considered_species is a list containing the other species the adopter will consider
Their score should be 1x their desired species + .3x all of their desired species
"""
def __init__(self, name, desired_species, considered_species):
Adopter.__init__(self, name, desired_species)
self.considered_species = considered_species
def get_score(self, adoption_center):
num_Other = 0
for animal in self.considered_species:
if adoption_center.get_number_of_species(animal) > 0:
num_Other += adoption_center.get_number_of_species(animal)
adopter_score = Adopter.get_score(self, adoption_center)
score = adopter_score + 0.3 * num_Other
return score
def __str__(self):
return "%s and score is %d" % (self.name, self.get_score)
class FearfulAdopter(Adopter):
"""
A FearfulAdopter is afraid of a particular species of animal.
If the adoption center has one or more of those animals in it, they will
be a bit more reluctant to go there due to the presence of the feared species.
Their score should be 1x number of desired species - .3x the number of feared species
"""
def __init__(self, name, desired_species, feared_species):
Adopter.__init__(self, name, desired_species)
self.feared_species = feared_species
def get_score(self, adoption_center):
num_feared = adoption_center.get_number_of_species(self.feared_species)
adopter_score = Adopter.get_score(self, adoption_center)
score = adopter_score - (0.3 * num_feared)
return max(0.0, score)
def __str__(self):
return "%s and score is %d" % (self.name, self.get_score)
class AllergicAdopter(Adopter):
"""
An AllergicAdopter is extremely allergic to a one or more species and cannot
even be around it a little bit! If the adoption center contains one or more of
these animals, they will not go there.
Score should be 0 if the center contains any of the animals, or 1x number of desired animals if not
"""
def __init__(self, name, desired_species, allergic_species):
Adopter.__init__(self, name, desired_species)
self.allergic_species = allergic_species
def get_score(self, adoption_center):
for animal in self.allergic_species:
if animal in adoption_center.get_species_count().keys():
return 0.0
return 1.0 * adoption_center.get_number_of_species(self.desired_species)
def __str__(self):
return "%s and score is %d" % (self.name, self.get_score)
I've tried placing __str__ and __repr__ methods in the various classes. What I've read suggests __str__ is what I'm after. I've also tried placing a simple "for loop" with a print statement in the function body itself. This latter approach lead to a screen full of errors. I've printed using __str__ before with success, but everything seems to be failing me on this one. Any insight would be appreciated.
As per your comment, you are printing these within a list. The print function retrieves the string representation of each argument to be printed, defined by __str__. The string representation of a list consists of square brackets enclosing a comma+space-separated sequence of the repr representation of each item, defined by __repr__.
>>> class A:
... def __str__(self):
... return 's'
... def __repr__(self):
... return 'r'
...
>>> l = [A(), A()]
>>> print(l)
[r, r]
>>> print(*l)
s s
If you want to see the human-readable string representation of each item, either pass them directly to the print function with the * unpacking operator, or loop over that list and call print on each item. If you want to see a human-readable string representation of each item when you directly print the list that holds them, you can define a __repr__ that returns the same thing as the __str__ method does, but it's not recommended, as that's supposed to be a way of reproducing the object with eval.