0

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!

Sue-May Xu
  • 460
  • 2
  • 9
  • 16
  • 1
    Try defining `__repr__`. Rename your `__str__` to `__repr__` and define `__str__` in terms of `__repr__`. – Paul Rooney Jun 29 '18 at 22:42
  • Possible duplicate of [How do I change the string representation of a Python class?](https://stackoverflow.com/questions/4912852/how-do-i-change-the-string-representation-of-a-python-class) – OneCricketeer Jun 29 '18 at 23:00
  • I don't think you're running the shown code because `len(values)` should throw an error – OneCricketeer Jun 29 '18 at 23:02
  • 1
    probably you should also have a Menu class that is separate from your Food class. it doesn't make sense to me to have the buildMenu function as a part of an individual Food object. – David Zemens Jun 29 '18 at 23:18
  • It’s not clear (as witnessed by variance in answers) of your expected output. Adding output value or ticking an accepted answer would clear that up. – Paul Rooney Jul 04 '18 at 09:18

3 Answers3

1

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]

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
David Gaertner
  • 386
  • 2
  • 7
0

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:

enter image description here

David Zemens
  • 53,033
  • 11
  • 81
  • 130
0

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))
Blckknght
  • 100,903
  • 11
  • 120
  • 169