Python tuition calculator

I'm a student learning Python, I made this calculator that will tell you the tuition for the next 5 years at an increase of 3% per year. How can I improve on this and did I do anything that isn't best practice? To revise my new version, Python tuition calculator 2.0

inState = 10000
outState = 24000

years = []
tuitionIncrease = []

i = raw_input('Please input your type of residency, I for in-state, O for out-of-state, and G for graduate: ')

if i == 'I':
costOfTuition = inState
elif i == 'O':
costOfTuition = outState
elif i == 'G':

x = 0
while x != 5:
intMath = costOfTuition * 0.03
tuitionIncrease.append(intMath)
fnlMath = intMath + costOfTuition
years.append(fnlMath)
costOfTuition = fnlMath
x += 1

academicYear1 = "${:,.2f}".format(years[0]) academicYear2 = "${:,.2f}".format(years[1])
academicYear3 = "${:,.2f}".format(years[2]) academicYear4 = "${:,.2f}".format(years[3])
academicYear5 = "${:,.2f}".format(years[4]) academicYear1Inc1 = "${:,.2f}".format(tuitionIncrease[0])
academicYear1Inc2 = "${:,.2f}".format(tuitionIncrease[1]) academicYear1Inc3 = "${:,.2f}".format(tuitionIncrease[2])
academicYear1Inc4 = "${:,.2f}".format(tuitionIncrease[3]) academicYear1Inc5 = "${:,.2f}".format(tuitionIncrease[4])

totalTuitionIncreaseSum = sum(tuitionIncrease)
totalTuitionIncrease = "${:,.2f}".format(totalTuitionIncreaseSum) 4 print('UNDERGRADUATE TUITION FOR THE NEXT FIVE YEARS ') print('ACADEMIC YEAR TUITION INCREASE ') print('------------- ------------ -------- ') print('2016-17 ' + academicYear1 + ' ' + academicYear1Inc1) print('2017-18 ' + academicYear2 + ' ' + academicYear1Inc2) print('2018-19 ' + academicYear3 + ' ' + academicYear1Inc3) print('2019-20 ' + academicYear4 + ' ' + academicYear1Inc4) print('2020-21 ' + academicYear5 + ' ' + academicYear1Inc5) print('TOTAL TUITION INCREASE ' + totalTuitionIncrease)  2 Answers Your naming is a bit unPythonic. Most variable and function names should be snake_case, so tuitionIncrease should be tuition_increase. But constants should be UPPER_SNAKE_CASE, meaning inState is IN_STATE. You should also use clear names even if they're briefly used. i for input isn't great, as i is often used in for loops. Instead, you could use something like residency, that matches what the value means. Speaking of those constants, you should actually put the three of them into a dictionary instead. A dictionary takes a string as a key and returns and associated value. So you can cut out the middle man and pass the user's input into the dictionary to get the number you need. RESIDENCY_COST = { "I": 10000, "O": 24000, "G": 40000, }  About that input. You don't handle cases where the user enters input wrong, or if they enter a valid letter but as lowercase. Luckily we can do both of these easily. For avoiding the lowercase problem, use the str.upper() method. It turns all charactes in a string into uppercase so even if someone enters 'i' you'll change it to 'I'. The way you can handle invalid input is by trying to get the value from the dictionary from above. You access values in a dictionary with the syntax dictionary[key] and you can write code so that you attempt to pass a key and if the key doesn't exist Python handles it. Here's how it would look: residency = raw_input('Please input your type of residency, I for in-state, O for out-of-state, and G for graduate: ') try: cost_of_tuition = RESIDENCY_COST[residency.upper()] except KeyError: print ('Please enter I, G or O ONLY.')  But that's no good, that means we tell the user what to do and they don't get a second attempt. That's why you can wrap the whole thing in an infinite while loop and break it when you get valid input. while True: residency = raw_input('Please input your type of residency, I for in-state, O for out-of-state, and G for graduate: ') try: cost_of_tuition = RESIDENCY_COST[residency] break except KeyError: print ('Please enter I, G or O ONLY.')  This will keep running the code in the while block forever until it reaches the break command. It can only reach there after a correct key is entered and cost_of_tuition has been set. Instead of using this while x != 5, you can use a simple for loop. for x in range(5):  Though since you don't need x, it's Python style to instead say for _ in range(5) to show that _ isn't a value you're actually using. This block of calculation is a little unclear. What does intMath and fnlMath mean? Clearer names about the purpose and context of the values makes code infinitely more readable.  intMath = costOfTuition * 0.03 tuitionIncrease.append(intMath) fnlMath = intMath + costOfTuition years.append(fnlMath) costOfTuition = fnlMath  Also, have a loop where you append to lists, but then you manually read both those lists to create sets of 5 very similar values that should be lists. Why not make these directly in your loop? I'd change the loop block to this:  intMath = cost_of_tuition * 0.03 tuition_increase.append("${:,.2f}".format(intMath))
fnlMath = intMath + costOfTuition
academic_years.append("${:,.2f}".format(fnlMath)) cost_of_tuition = fnlMath  Of course you need the sum too, but instead of using sum, just create the sum in the for loop you're already doing.  total_tuition_increase += intMath tuition_increase.append("${:,.2f}".format(intMath))


You still need to format it, but you can do that within the print command:

print('TOTAL TUITION INCREASE              ${:,.2f}'.format(total_tuition_increase))  You seem to have misunderstood format. It's not intended primarily to be a variable converter, it's actually mainly for inserting values into strings, as I showed above. It has other handy features too, like specifying column widths so that spaces match up. So you could print one of your results like this instead: print('2016-17 {:>10} {:>10}'.format(academic_years[0], tuition_increase[0]))  The 10 tells Python to use 10 spaces regardless of how long the string is, and the > makes it right justified. This will make it neater to read. I also think that since you have actual lists now, you could loop over them instead. You can use zip to attach 2 lists together and that way iterate over both at once. You will also need to loop over the year to achieve this (otherwise you'd print the same year every time). You can do that using a BASE_YEAR constant and using enumerate to see what iteration you're on. Here's how the loop would look: BASE_YEAR = 16 for i, (tuition, increase) in enumerate(zip(academic_years, tuition_increase)): print('20{}-{} {:>10} {:>10}'.format(i + BASE_YEAR, i + 1 + BASE_YEAR, tuition, increase))  • Thank you so much for the thorough feedback, I appreciate it. I'm going to make the changes to my code later today. @SuperBiasedMan Commented Sep 30, 2015 at 11:11 • @Xarotic Glad to help! If anything is confusing or unclear, just ask. And when you've finished making changes, you're free to post another question on here as a follow up if you'd like to get feedback on that new version. Commented Sep 30, 2015 at 11:13 • I couldn't wait until after class, I jumped on it this morning and I'm trying to replace what you told me with what I have working. Commented Sep 30, 2015 at 11:27 • Although I'm not sure If I'm improving anything or making a giant mess haha. Maybe I need to redo the whole thing with suggested code.. Commented Sep 30, 2015 at 11:34 • @Xarotica Sometimes restarting is the most helpful so you get a clean slate to rethink things. At least it's not a long script to restart! Commented Sep 30, 2015 at 11:39 If you're currently learning Python you should probably look at Python 3 more so than Python 2. There are only two violations for PEP8 (caught by the command-line tool, pep8), that's very good; line 9 can be split in a multitude of ways to go below the 80 character limit and there are more than one space before the plus in the last line. i = raw_input('Please input your type of residency, I for in-state, O for ' 'out-of-state, and G for graduate: ')  Also, constants should be uppercase with underscores, I'd say that applies to inState etc. IN_STATE = 10000 OUT_STATE = 24000 PROF_GRAD = 40000  That said, it would be easier to use a dictionary for this kind of selection (BASE_TUITION[i]) - that might be a bit less descriptive though. Btw. i isn't very descriptive either. Personally, I'd also stick with one kind of quotation marks, but YMMV. Now for the code and other conventions. First, code would usually be put into functions to make it reusable. I don't know if you're that far ahead, just to note that it would be nice to split the input, processing and output parts into separate units. There is no error handling for invalid input. If I enter foo I'd expect a (helpful) error message from the program, not a NameError as in the current state. For example, using the following loop, the program will only handle valid input and print at least an indicator that something went wrong: costOfTuition = None while costOfTuition is None: i = raw_input('Please input your type of residency, I for in-state, O for ' 'out-of-state, and G for graduate: ') if i == 'I': costOfTuition = IN_STATE elif i == 'O': costOfTuition = OUT_STATE elif i == 'G': costOfTuition = PROF_GRAD else: print("Invalid input.")  The while loop would be more readable using for and range. Since x isn't actually used, _ can be used instead. for _ in range(5): intMath = costOfTuition * 0.03 tuitionIncrease.append(intMath) fnlMath = intMath + costOfTuition years.append(fnlMath) costOfTuition = fnlMath  The assignments to academicYear1 to 5 should be a warning sign. If that happens in code it's usually an indicator that it can be more easily achieved with less variables (and less typing). years = [] tuitionIncrease = [] academicYear = [] academicYear1Inc = [] for _ in range(5): intMath = costOfTuition * 0.03 tuitionIncrease.append(intMath) fnlMath = intMath + costOfTuition years.append(fnlMath) costOfTuition = fnlMath academicYear.append("${:,.2f}".format(fnlMath))
academicYear1Inc.append("${:,.2f}".format(intMath))  If you want it in separate loops, that's fine too. Same goes for the sum call at the end. It's nicer to look at, so I kept it around. Lastly, the formatting is mostly good with using format. The last print statements can be written in a nicer way though. All in all: IN_STATE = 10000 OUT_STATE = 24000 PROF_GRAD = 40000 costOfTuition = None while costOfTuition is None: residency = raw_input('Please input your type of residency, I for ' 'in-state, O for out-of-state, and G for graduate: ') if residency == 'I': costOfTuition = IN_STATE elif residency == 'O': costOfTuition = OUT_STATE elif residency == 'G': costOfTuition = PROF_GRAD else: print("Invalid input.") years = [] tuitionIncrease = [] academicYear = [] academicYear1Inc = [] for _ in range(5): intMath = costOfTuition * 0.03 tuitionIncrease.append(intMath) fnlMath = intMath + costOfTuition years.append(fnlMath) costOfTuition = fnlMath academicYear.append("${:,.2f}".format(fnlMath))
academicYear1Inc.append("${:,.2f}".format(intMath)) totalTuitionIncreaseSum = sum(tuitionIncrease) totalTuitionIncrease = "${:,.2f}".format(totalTuitionIncreaseSum)

print('UNDERGRADUATE TUITION FOR THE NEXT FIVE YEARS ')