Unexpected “None” in the output


#1

Hi! Sorry, I’m new here so I might be asking something I should ask somewhere else… :sweat_smile: Anyway, I have a problem with “Basta Frazoolin’” project as well: I get an unexpected “None” in the output, and I can’t understand why… can anyone help me?

class Menu:
  def __init__(self, name, items, start_time, end_time):
    self.name = name
    self.items = items
    self.start_time = start_time
    self.end_time = end_time
    
  def calculate_bill(self, purchased_items):
    self.purchased_items = purchased_items
    bill = 0
    for item in self.purchased_items:
      if item in self.items:
        bill += self.items[item]
      else:
        return "You selected an item that is not in our menu."
    return "Bill: ${}".format(bill)
  
  def __repr__(self):
    return "The \"{name}\" menu is available from {start_hour} to {end_hour}.".format(name=self.name, start_hour=self.start_time, end_hour=self.end_time)
      
brunch = Menu("Brunch", {'pancakes': 7.50, 'waffles': 9.00, 'burger': 11.00, 'home fries': 4.50, 'coffee': 1.50, 'espresso': 3.00, 'tea': 1.00, 'mimosa': 10.50, 'orange juice': 3.50}, 11, 16)
early_bird = Menu("Early Bird", {'salumeria plate': 8.00, 'salad and breadsticks (serves 2, no refills)': 14.00, 'pizza with quattro formaggi': 9.00, 'duck ragu': 17.50, 'mushroom ravioli (vegan)': 13.50, 'coffee': 1.50, 'espresso': 3.00}, 15, 18)
dinner = Menu("Dinner", {'crostini with eggplant caponata': 13.00, 'ceaser salad': 16.00, 'pizza with quattro formaggi': 11.00, 'duck ragu': 19.50, 'mushroom ravioli (vegan)': 13.50, 'coffee': 2.00, 'espresso': 3.00}, 17, 23)
kids = Menu("Kids", {'chicken nuggets': 6.50, 'fusilli with wild mushrooms': 12.00, 'apple juice': 3.00}, 11, 21)

class Franchise(Menu):
  def __init__(self, address, menus):
    self.address = address
    self.menus = menus
    
  def available_menus(self, time):
    for menu in self.menus:
      if time in range(menu.start_time, menu.end_time):
        print("Order an item from the \"{}\" menu:".format(menu.name))
        for plate in menu.items.keys():
          print("  {}  ${}".format(plate, menu.items[plate]))
    if time not in range(11, 23):
      print("The restaurant is closed")
        
  def __repr__(self):
    return "The restaurant is located in: {}.".format(self.address)

flagship_store = Franchise("1232 West End Road", [brunch, early_bird, dinner, kids])
new_installment = Franchise("12 East Mulberry Street", [brunch, early_bird, dinner, kids])

print(flagship_store.available_menus(17))

The output is a list of food per menu with price, but followed by “None”.


Learn Python: Classes: Basta Fazoolin'
#2

It can be ignored. print() has no return value so the console echoes None on completion of that last instruction.


#3

Which means I should use return instead of print() inside the classes…?


#4

It’s a minor detail that can be ignored as it’s behond our control.


#5

Oh ok, I got it! Well, thank you very much! :grinning:


#6

Instead of …

print(flagship_store.available_menus(17))

… you could either use this to call the available_menus method as you have it now …

flagship_store.available_menus(17)

… or use return in the available_menus method instead of print.


#7

The problem is that if I use return instead of print() it prints only the line:

print("Order an item from the \"{}\" menu:".format(menu.name))

and the same happens in the following project, with:

class Marketplace(Art):
  def __init__(self, listing):
    self.listing = listing
    self.listing = []
    
  def add_listing(self, new_listing):
    self.listing.append(new_listing)
    return self.listing
  
  def remove_listing(self, to_be_removed):
    self.listing.remove(to_be_removed)
    return self.listing
  
  def show_listings(self):  #Prints all "elem"s + None
    for i in self.listing:
      for elem in i:
        print(elem)
    
# TEST
veneer = Marketplace([])
veneer.add_listing([girl_with_mandolin, girl_with_mandolin, girl_with_mandolin])
print(veneer.show_listings())

meaning that return returns only one girl_with_mandolin instead of all three, as happened in the previous project.
Why does it happen?


#8

To have the method return content similar to that which it printed, you cannot simply replace each print statement with a return statement. One alternative you have is to accumulate the results in a variable, and specify that variable in a return statement after the results are complete.

The following is your available_menus method with its return statements …

  def available_menus(self, time):
    for menu in self.menus:
      if time in range(menu.start_time, menu.end_time):
        print("Order an item from the \"{}\" menu:".format(menu.name))
        for plate in menu.items.keys():
          print("  {}  ${}".format(plate, menu.items[plate]))
    if time not in range(11, 23):
      print("The restaurant is closed")

The following revision accumulates the results in a variable, as suggested above. …

  def available_menus(self, time):
    result = ""
    for menu in self.menus:
      if time in range(menu.start_time, menu.end_time):
        result += "\nOrder an item from the \"{}\" menu:".format(menu.name)
        for plate in menu.items.keys():
          result += "\n  {}  ${}".format(plate, menu.items[plate])
    if time not in range(11, 23):
      result += "\nThe restaurant is closed"
    return result

#9

Thank you very much, it worked!! :smiley:
So, this means that when I use def I have to return a variable, and not print() it… besides, I shouldn’t return a string, but add strings to the variable I have to return… Am I right?


#10

When designing a function, you can choose either strategy. However, if you return a value, instead of printing the result, it quite often affords the programmer more flexibility regarding how that value can be used.

The returned value does not have to be expressed as a variable. You can specify a more complex expression in the return statement.

It depends upon the algorithm that is being used. The crux of the matter is that when a return statement is encountered, execution of the function terminates, a value is returned, and control of execution continues outside the function, where the function was called. In the current case, you had some if statements, a loop, and several print statements within the function. If you simply replaced each print statement with a return statement, then the first return statement that got executed would terminate execution of the function before the complete result was computed.


#11

Thank you very much! Now I understand better how it works :grin: