Is there another way to optimize the efficiency of this code?

Hello, I am just wondering if I could play around with my code to make it shorter and easier to read.

My code when initiated works like this (some parts are going to be skipped):
It first goes to the main() function, then when the user inputs number 2, it navigates to the foodShopping() function, where the user will be choosing the brand type and the method (this one is within the foodShopping() function) of buying their food. I coded in a way that in the foodShopping() function there is another function in it called the calculatePrice() function.
I was wondering if it is possible to lessen the lines (can be found on the image below) so they don’t have to be repeated.

There is no need to give the full answer, just give me an idea of what to do; I want to figure this out by myself.

Thanks!
(p.s., there are still a lot of names for me to change, so I apologize if they sound confusing.)

Here is the part where I am specifically stuck at:
#Stuck-part:

def foodShopping():

print("\n1. Mash\n2. Pellets\n3. Enhanced Food")
chooseBrand = input("\nChoose brand type: ")
def calculatePrice():
    print("\n1. Kilogram\n2. Bag\n3. Back")
    chooseMethod =input("Choose method: ")
    if chooseBrand == '1' and chooseMethod == '1':
        calculateKilo(MASH_TEN, MASH_FIFTY)
    elif chooseBrand == '1' and chooseMethod == '2':
        calculateBag(MASH_TEN, MASH_FIFTY)
    elif chooseBrand == '2' and chooseMethod == '1':
        calculateKilo(PELLET_TEN, PELLET_FIFTY)
    elif chooseBrand == '2' and chooseMethod == '2':
        calculateBag(PELLET_TEN, PELLET_FIFTY)
    elif chooseBrand == '3' and chooseMethod == '1':
        calculateKilo(EFOOD_TEN, EFOOD_FIFTY)
    elif chooseBrand == '3' and chooseMethod == '2':
        calculateBag(EFOOD_TEN, EFOOD_FIFTY)
    else:
        wrongInput()
        calculatePrice()

#Another Stuck-part (within the foodShopping() function:

if chooseBrand != '1' and chooseBrand != '2' and chooseBrand != '3':
    wrongInput()
    foodShopping()
calculatePrice()

Here is my code:

MASH_TEN=20.50
MASH_FIFTY=90

PELLET_TEN=22.75
PELLET_FIFTY=100

EFOOD_TEN=25.5
EFOOD_FIFTY=125

def main():

print("Welcome to Chook Fake Felector")
print("1. Chicken food brand informant")
print("2. Beef food shopping")
print("3. Exit\n")
mChoice = input("Enter a number from the menu above to proceed: ")
if mChoice == '1':
    info() #deleted
elif mChoice == '2':
    foodShopping()
elif mChoice == '3':
    exit()
else:
    wrongInput()
    main()

#Stuck-part:

def foodShopping():

print("\n1. MashPotato\n2. Starch\n3. E Food")
chooseBrand = input("\nChoose brand type: ")

def calculatePrice():
    print("\n1. Kilogram\n2. Bag\n3. Back")
    chooseMethod =input("Choose method: ")
    if chooseBrand == '1' and chooseMethod == '1':
        calculateKilo(MASH_TEN, MASH_FIFTY)
    elif chooseBrand == '1' and chooseMethod == '2':
        calculateBag(MASH_TEN, MASH_FIFTY)
    elif chooseBrand == '2' and chooseMethod == '1':
        calculateKilo(PELLET_TEN, PELLET_FIFTY)
    elif chooseBrand == '2' and chooseMethod == '2':
        calculateBag(PELLET_TEN, PELLET_FIFTY)
    elif chooseBrand == '3' and chooseMethod == '1':
        calculateKilo(EFOOD_TEN, EFOOD_FIFTY)
    elif chooseBrand == '3' and chooseMethod == '2':
        calculateBag(EFOOD_TEN, EFOOD_FIFTY)
    else:
        wrongInput()
        calculatePrice()

#Another Stuck-part:

if chooseBrand != '1' and chooseBrand != '2' and chooseBrand != '3':
    wrongInput()
    foodShopping()
calculatePrice()

#----------------------------------------------------------------------
def calculateKilo(priceTen, priceFifty):

kgInput = int(input("Enter kg: "))
if kgInput % 10 == 0:
    tenKilo = (kgInput % 50) // 10 * priceTen
    fiftyKilo = int(kgInput / 50) * priceFifty
    print("Your order is: {0:,.0f} ten-kilo(s) and {1:,.0f} fifty-kilo(s)".format(tenKilo // priceTen, fiftyKilo // priceFifty))
    return print("Your price is: ${0:,.2f}. Thank you!".format(tenKilo + fiftyKilo))
else:
    wrongInput()
    calculateKilo(priceTen, priceFifty)

def calculateBag(priceTen, priceFifty):

bagTen = int(input("Enter 10 kg bag: ")) * priceTen
bagFifty = int(input("Enter 50 kg bag: ")) * priceFifty
print("The total kilogram(s) is: {0:,.0f} kg.".format((bagTen // priceTen) * 10 + (bagFifty // priceFifty) * 50))
return print("Your price is: ${0:,.2f}. Thank you!", bagTen + bagFifty)

def exit():

print("Thank you! Please come again.")

def wrongInput():

print("\nENTER THE CORRECT NUMBER.\n")

main()

Some ideas to consider.

  • use data structures to hold variables, something like:
brands = {'1': 20.50, '2': 22.75, '3': 25.5}
methods = {'1': 90, '2': 100, '3': 125}

# if you have validated input from user then just do
print(brands[choice], methods[choice])
  • use validation function to take user input, something like:
def validate(request, allowed):
    while (answer := input(request)) not in allowed:
        print(f'Expected one from {", ".join(allowed)} but {answer!r} was entered')
    return answer
  • take advantage of loops if similar request is made (not very readable though):
brand, method = (validate(request=f'Choose {item}: ', allowed=('1', '2', '3')) 
                 for item in ('brand', 'method'))
1 Like

As the old expression goes, “premature optimization is the root of all evil”.

In general, particularly at this point in your programing journey, its not really worth “optimizing” for “efficiency” but rather readability, simplicity and extensibility. Indeed, from your description, it sounds like that’s actually what you mean, but I just wanted to emphasize that point.

A few more small tips, besides what @aivarpaalberg suggests:

  • Good job using top-level constants for magic numbers! That is likely to really come in handy down the line if and when you want to change something, or just understand what the heck “42” is supposed to mean.

  • Here:

    return print("Your price is: ${0:,.2f}. Thank you!".format(tenKilo + fiftyKilo))
    

    and here:

    return print("Your price is: ${0:,.2f}. Thank you!".format(tenKilo + fiftyKilo))
    

    you are returning the result of print(), which is None; print() does not return a value, but rather has side effects (of printing to the screen). You should either omit the return, or actually return the constructed string and have the caller print it.

  • Extending @aivarpaalberg 's suggestions to use dicts instead of long if/elif blocks, you can do the same thing for dispatching to different functions based on the user’s choices. For example, including error handling if the user selects an invalid one:

    COMMANDS = {'1': info, '2': foodShopping, '3': exit}
    try:
        COMMANDS[mChoice]()
    except KeyError:
        wrongInput()
        main()
    
  • Instead of

    if chooseBrand != '1' and chooseBrand != '2' and chooseBrand != '3':
    

    you can just do

    if chooseBrand not in {'1', '2', '3'}
    

    (Or better yet, instead of a set literal, .keys() of some dict that you’re using for your lookup table)

  • You can use f-strings instead of format, which are shorter, faster and more elegant. So instead of

    "Your price is: ${0:,.2f}. Thank you!".format(tenKilo + fiftyKilo)
    

    you can just do

    f"Your price is: ${tenKilo + fiftykilo:,.2f}. Thank you!"
    
  • As you do on the line before, you don’t need to do int(kgInput / 50); kgInput // 50 produces the same result.

  • In Python, per PEP 8 and standard convention, functions and variables are given snake_case names, whereas CamelCase is reserved for classes. Additionally, functions should generally be given names that are verbs (since they are an action), while data variables should be nouns (since they are things). Currently, they are actually the opposite, which is rather confusing to readers (and maybe you in the future), as the variables/objects have names of actions (chooseMethod, chooseBrand) while the functions have names of nouns (info, foodShopping, etc). So, for example, you’d want to use brand_choice instead of chooseBrand and shop_for_food() instead of foodShopping().

1 Like