6
\$\begingroup\$

I have, after years of excuses, started programming. Well honestly, I was not able to find any one interested in helping me with my start-up idea. So I had no choice but to ask myself 'How hard can this be?' and here I am.

Here is a Python program for a simple calculator of my own budgets and savings. I have used basic Python concepts to write this code. The way I am learning is hands-on without theory as it immensely monotonous.(Suggest me some interesting 📚 too.)

Here is my code. I am curious to know what coding concepts I can use to make this a shorter, efficient and a better code. All the inputs will be genuinely respected.


salary = float(input("Enter your total salary per month: "))

savings = float(input("Enter your savings percentage: "))

emi = float(input("What is your total emi percent:"))

budget = float(input("how much do you want to save?:"))

duration = float(input("how many months do you have?:"))



tfinal = salary-((savings/100)*salary) #total salary left after savings are subtracted

final_left = tfinal-((emi/100)*salary) #total salary left after savings and emi removed

percent_left = 100-(savings+emi) #total percentage of salary left after savings and emi removed in percent

final_budget = final_left*duration #monthly saving multiplied by duration for final amount left

sav_per_month = (budget/duration) #final budget savings you are planning per month



if sav_per_month < final_left:
    print ("it is possible \nearning {} rupees {} percent left and save {} rupees per month".format(final_left,percent_left,sav_per_month))
else:
    print ("it is not possible \nearning {} rupees {} percent left and you want to save {} rupees per month?".format(final_left,percent_left,sav_per_month))


print "you will be left with:", final_budget
\$\endgroup\$
7
  • 1
    \$\begingroup\$ Are those Indian rupees (₹), Pakistani rupees (₨) or something else? \$\endgroup\$
    – Reinderien
    Feb 9 at 14:54
  • \$\begingroup\$ A good book that I recommend is Automate the Boring Stuff with Python. It does a good job of covering the basics of Python and showing how one might do some of the things people commonly use Python for (such as Web scraping, working with csv/Excel files, and auto form filling). As a bonus, it's also free on the author's website! \$\endgroup\$
    – Unknown
    Feb 10 at 0:50
  • 1
    \$\begingroup\$ @Reinderien: It is Indian rupees. \$\endgroup\$
    – user175008
    Feb 10 at 6:54
  • \$\begingroup\$ @Unknown: Thanks for the recommendation. I'll definitely go through it. \$\endgroup\$
    – user175008
    Feb 10 at 6:54
  • 1
    \$\begingroup\$ If this is just code to practice your coding skills, then don't worry too much about this. But, for real code, never use floats for currency. \$\endgroup\$
    – marcelm
    Feb 10 at 12:31

4 Answers 4

7
\$\begingroup\$

Welcome to Code Review! There are two things that need to be addressed, but these are not that obvious. Apart from them, the program's math seems to be fine.

Python version

The last line reveals that you're using Python 2, which has reached its end-of-life two years ago and therefore shouldn't be used for new projects anymore. Use a recent Python 3 version instead.

The only thing you'd need to change here would be the lines containing a print. As this is a function like input() in Python 3 and not a statement like if, you'd change things like this:

# Python 2             Python 3
  print "x"            print("x")
  print "x", y         print("x", y)
  print "x".format(y)  print("x".format(y))

It so happens to be that the prints in the if...else use redundant (), making them Python 3-compatible. You'd only need to change the last print.

Input checking

As is, the program would throw an exception when the user inputs an invalid number, which can easily happen if you hit a wrong key by accident. The program should instead ask the user over and over, catching said exceptions until a valid float is typed in. This procedere should be put into a function that gets the question as a parameter and returns the valid float.

How this is done in detail is left as an exercise for the reader. All you'd need to find out is how to write and use a function and how to use the while, break and try...except: statements.


Sadly, I can't recommend any books as I've learned mostly hands-on myself. Good coding style will need some theory though, so I'd recommend looking into a style guide such as PEP 8.

\$\endgroup\$
1
  • \$\begingroup\$ Very helpful mindoverflow, I am actually trying out loops and how to embed them into the code. I presume, those are primarily for use where we need to make sure something has to be put in a certain format or reduce the redundancy of repeated lines of code. \$\endgroup\$
    – user175008
    Feb 10 at 6:59
6
\$\begingroup\$
  • Keep fractional variables (0-1) instead of percentile variables (0-100) as the former are more "math-native" and can use in-built percent formatting
  • Try to make your prompts follow a more consistent lexical pattern; the example I've shown has a single "Enter" prompt at the top followed by a series of object phrases
  • Use built-in currency formatting. hi_IN offers a rendered rupee symbol. Prefer this symbol over hard-coding and spelling out "rupees". One of the several advantages of locale support is that it correctly renders the (interesting!) lakh digit group separation.
  • Use Python 3.

Suggested

from locale import setlocale, LC_ALL, currency, localeconv
setlocale(LC_ALL, 'hi_IN.UTF-8')
symbol = localeconv()['currency_symbol']

print('Enter...')
salary = float(input(f'your monthly salary: {symbol}'))
savings = float(input('your monthly savings: %'))/100
emi = float(input('your equated monthly installment (EMI): %'))/100
budget = float(input(f'the total amount you want to save: {symbol}'))
duration = float(input('how many months you have: '))


def fmoney(money: float) -> str:
    return currency(money, grouping=True)


tfinal = salary*(1 - savings)       # total salary left after savings are subtracted
final_left = tfinal - emi*salary    # total salary left after savings and emi removed
percent_left = 1 - savings - emi    # total percentage of salary left after savings and emi removed in percent
final_budget = final_left*duration  # monthly saving multiplied by duration for final amount left
sav_per_month = budget/duration     # final budget savings you are planning per month

if sav_per_month < final_left:
    possible = 'possible'
    can = 'can'
else:
    possible = 'not possible'
    can = 'cannot'

print(
    f'It is {possible}.'
    f'\nEarning {fmoney(final_left)} with {percent_left:.1%} left,'
    f' you {can} save {fmoney(sav_per_month)} per month.'
    f'\nYou will be left with {fmoney(final_budget)}.'
)

Output

Enter...
your monthly salary: ₹50000
your monthly savings: %5
your equated monthly installment (EMI): %15
the total amount you want to save: ₹100000
how many months you have: 3
It is possible.
Earning ₹40,000.00 with 80.0% left, you can save ₹33,333.33 per month.
You will be left with ₹1,20,000.00.
\$\endgroup\$
3
  • \$\begingroup\$ The last two prints contain long strings which are almost the same. What about using a single parametrized string? \$\endgroup\$ Feb 9 at 17:26
  • \$\begingroup\$ @pabouk sure; edited \$\endgroup\$
    – Reinderien
    Feb 9 at 22:17
  • 1
    \$\begingroup\$ Appreciate this. This is very neat and useful. Thanks for the input. Will surely keep these in mind for further programming. I'd have never known python has in-built handling for currency. Although some of the code is too technical right now for me, It is very relatable. Thanks again. \$\endgroup\$
    – user175008
    Feb 10 at 7:06
2
\$\begingroup\$

Here are three concepts that will go a long way in making the above code shorter, efficient, and better overall code. The following research topics such as functions, exception handling, and loops will do you well to learn early on.

# user defined function that will return the result of the users input as a float
# while this is exactly what you are doing, and is kind of redudant, it will make more
# sense with future concepts. 
def user_input(txt):
    result = input(txt)

    return float(result)

salary = user_input("Enter your total salery per month: ")

I understand that you may not have hit this point, but your current application will generate an exception if you enter anything other than int or float. Thus you should be checking your input type.

# user defined function that will validate and return the result of the users input
def validate_user_input(txt):

    # try catch is a means of handling exceptions without crashing the program. 
    # The code within the try block with be attempted, if everything goes well, then it moves on. 
    # if an error occurs than the Except block is triggered. 
    try:
        result = float(input(txt))
    except Exception as e: # Exception e is generic. I wouldn't go as far as saying it shouldn't be used, 
                            # but its a good idea to catch specific exceptions. Its generic here, as
                            # you should look into exception handling. 
        print('Exception: %s', e)
        quit() # shuts down script gracefully

    return result

savings = validate_user_input("Enter your savings percentage: ")

The next concept would be loops, which would allow you to loop your questions if the user didn't input a correct type.

# user defined function that will validate and loop if the user input is invalid. 
def validateLoop_user_input(txt):
    valid = False # this is a flag, we change the flag when we want something to happen. 

    while not valid: # looking at the flag, we will continue the loop until valid is not false
        try: # again we are using the try-except concept
            result = float(input(txt))
            valid = True  # if the user input is a float, then valid is set to true and the loop ends. 
        except Exception as e:
            print("User Input Error, please re-enter proper value: ")

    return result

emi = validateLoop_user_input("What is your total emi percent:")

I should point out, just in case, you wouldn't want to use all three of the functions in your code, just the last one, I separated them to show you different concepts.

here is what It would look like.

def validateLoop_user_input(txt):
    valid = False

    while not valid:
        try:
            result = float(input(txt))
            valid = True
            
        except Exception as e:
            print("User Input Error, please re-enter proper value: ")

    return result

salary = validateLoop_user_input("Enter your total salery per month: ")
savings = validateLoop_user_input("Enter your savings percentage: ")
emi = validateLoop_user_input("What is your total emi percent:")
budget = validateLoop_user_input("how much do you want to save?:")
duration = validateLoop_user_input("how many months do you have?:")


tfinal = salary-((savings/100)*salary) #total salary left after savings are subtracted
final_left = tfinal-((emi/100)*salary) #total salary left after savings and emi removed
percent_left = 100-(savings+emi) #total percentage of salary left after savings and emi removed in percent
final_budget = final_left*duration #monthly saving multiplied by duration for final amount left
sav_per_month = (budget/duration) #final budget savings you are planning per month

if sav_per_month < final_left:
    print ("it is possible \nearning {} rupees {} percent left and save {} rupees per month".format(final_left,percent_left,sav_per_month))
else:
    print ("it is not possible \nearning {} rupees {} percent left and you want to save {} rupees per month?".format(final_left,percent_left,sav_per_month))

print ("you will be left with:", final_budget)

Best of luck.

\$\endgroup\$
1
\$\begingroup\$

Welcome to the wonderful of (Python) programming.

You should study PEP 8 which is the Bible of every Python programmer. In fact, by looking at code formatting you can instantly tell newcomers to the language from more experienced programmers. It is expected that certain rules and coding style will be applied in a consistent manner. One important takeaway is the spacing rules for example.

Thus:

final_left = tfinal - emi*salary

would more "Pythonically" look like:

final_left = tfinal - emi * salary

Also, naming conventions for your functions, variable names, and whether to use lowercase or uppercase, and underscore: Naming Styles

PEP 8 is terse reading but not difficult. It is a question of habit. Get yourself a good IDE with a linter and some useful plugins that will help enforce good formatting.

If you're using at least Python 3.6, you'll have an additional option for printing out formatted variables: f-strings. A neat tutorial here: Python 3's f-Strings: An Improved String Formatting Syntax (Guide)

Then, this statement:

print ("it is not possible \nearning {} rupees {} percent left and you want to save {} rupees per month?".format(final_left,percent_left,sav_per_month))

could be written:

print(f"it is not possible \nearning {final_left} rupees {percent_left} percent left and you want to save {sav_per_month} rupees per month?")

which I find more clear and less error-prone because in the "classic" ways you have to pay attention to parameter order. Here the parameters are embedded inside the string that now looks more explicit.

And since you're handling floats, f-strings can also format values to the desired number of decimals, see here for examples.

There is a bit too much scrolling needed in your code. I suggest moving the inline comments eg:

# total salary left after savings are subtracted
tfinal = salary - ((savings / 100) * salary) 

# total salary left after savings and emi removed
final_left = tfinal - ((emi / 100) * salary) 

Then I can grasp the logic in a glance because the comments are neatly aligned and my eyes don't have to scan your code to find them.

My own rule of thumb: if you need to add more than a word or two of explanations, avoid inline comments. Add your comment on the line above.

Already addressed above by @Reinderien but to emphasize the point: Is is allowed to break up long lines into multiline statements like this for example (note that the leading f has to be repeated on each line that behaves as an f-string):

print(
    f"it is not possible \nearning {final_left} rupees {percent_left}"
    f"percent left and you want to save {sav_per_month} rupees per month?"
)

One way of avoiding \n for the line break is to use the triple quotes, those that you use for docstrings.

For example:

>>> print("""This is the first line
... and the second line""")
This is the first line
and the second line
\$\endgroup\$
2
  • \$\begingroup\$ Thanks Kate, I'd first be upgrading my python version to Python 3.x and then start using more advanced features. PEP 8 and the syntax corrections you mentioned do make sense to me. \$\endgroup\$
    – user175008
    Feb 10 at 7:14
  • \$\begingroup\$ I've downvoted this answer because I strongly disagree with the first paragraph. It is a bit too much of an exageration to state that pep8 is the bible of every Python programmer. In addition, if you turn to the page with spacing rules, it recommeneds the exact opposite, don't add spaces around the multiplication since it has a higher priority than the subtraction. python.org/dev/peps/pep-0008/#other-recommendations \$\endgroup\$
    – spyr03
    Feb 10 at 13:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.