Income tax calculator and global var problems
Question: Complete beginner here. I've been trying to pick up programming in my spare
time and don't really have any interactive resources to consult. I've tried my
best to get a program working where I've tried to program an income tax
calculator. I've pasted my program in its entirety.

What I'm hoping to understand from this is why the `tax_calc()` function is
not saving variable `payable`. I've created a test line

    
    
    print ('Test Tann:', tann,'Test Tmon', tmon,'Test tinc',tinc,'test payable',payable)
    

in order to check the var values and the only one that doesn't update is
`payable`. Is it a global var problem?

I'd also really appreciate any other advice regarding my coding. It's my first
program and I only really know how to use globals to change vars in this
regard despite a lot of experienced users expressing that the global call is
very unnecessary and messy or unpythonic. Also, whatever advice you have to
shorten or make my code more efficient is really appreciated.

    
    
    from decimal import *
    
    #Hmm, looks like I have to define all vars and dicts before functions even if I only call functions after declaration? 
    tinc = 0
    tann = 0
    tmon = 0
    age = 0
    payable = 0
    
    #Define calculation for specific tax brackets
    rates = {}
    rates['T1'] = 0.18 * tinc
    rates['T2'] = 29808 + (.25 * (tinc - 165600))
    rates['T3'] = 53096 + (.30 * (tinc - 258750))
    rates['T4'] = 82904 + (.35 * (tinc - 358110))
    rates['T5'] = 132894 + (.38 * (tinc - 500940))
    rates['T6'] = 185205 + (.40 * (tinc - 638600))
    
    #Defines the actual range for deciding on tax brackets
    tier = {}
    tier['T1'] = range(0,165600)
    tier['T2'] = range(165601,258750)
    tier['T3'] = range(258751,358110)
    tier['T4'] = range(358111,500940)
    tier['T5'] = range(500941,638600)
    tier['T6'] = range(638601, 5000000)
    
    #Defines the brackets for age variable 
    tierage = {}
    tierage['T1'] = 12080
    tierage['T2'] = 12080 + 6750
    tierage['T3'] = 12080 + 6750 + 2250
    
    #Asks for whether you want to enter monthly or annual salary
    def ask_choice():
        print ('Would you like to input monthly or annual salary? Please select (m/a)')
        global choice
        choice = str(input('> '))
    
    #Asks for age
    def ask_age():
        global age
        age = int(input("Please enter your age: "))
    
    #Asks for annual salary, all inputs done in floats to allow for cents
    def ask_annual():
        global tann, tinc
        tann = 0
        tann = float(input("Please enter your annual taxable income: "))
        tinc = tann
        print ('Your annual taxable income is',tinc)
    
    #Asks for monthly salary, all inputs done in floats to allow for cents
    def ask_monthly():
        global tmon, tinc
        tmon = 0
        tmon = float(input("Please enter your monthly taxable income: "))
        tinc = tmon*12
        print ('Your annual taxable income is',tinc)
    
    #Decides on and calls on which function to ask for for asking salary
    def asking():
        global error
        error = True
    #keeps looping until you enter Mm or Aa
        while error == True:
            if choice.lower() == "m":
                ask_monthly()
                error == False
                break
            elif choice.lower() == "a":
                ask_annual()
                error == False
                break
            else:
                print ("Input error, please input either 'a' to select annual or 'm' to select monthly")
                error == True
                ask_choice()
    
    
    def tax_calc():
        global payable, decpayable, tinc
        if tinc in tier['T1']:
            payable = rates['T1']
            print ('You fall in tax bracket 1')
        elif tinc in tier['T2']:
            payable = rates['T2']
            print ('You fall in tax bracket 2')
        elif tinc in tier['T3']:
            payable = rates['T3']
            print ('You fall in tax bracket 3')
        elif tinc in tier['T4']:
            payable = rates['T4']
            print ('You fall in tax bracket 4')
        elif tinc in tier['T5']:
            payable = rates['T5']
            print ('You fall in tax bracket 5')
        elif tinc in tier['T6']:
            payable = rates['T6']
            print ('You fall in tax bracket 6')
    
        decpayable = Decimal(payable).quantize(Decimal('0.01'))
        #Decimal used specifically for money, defines two decimal places. 
        print ('Tax before rebates: R',decpayable)
        print ('Test Tann:', tann,'Test Tmon', tmon,'Test tinc',tinc,'test payable',payable)
    
    def age_calc():
        global final
        if age < 65:
            final = payable - tierage['T1']
            print('You qualify for a primary rebate')
        elif 65 <= age < 75:
            final = payable - tierage['T2']
            print('You qualify for a primary and secondary rebate')
        elif age >= 75:
            final = payable - tierage['T3']
            print('You qualify for a primary, secondary and tertiary rebate')
    
        decfinal = Decimal(final).quantize(Decimal('.01'))
        print ('Annual tax after rebates is: R'+str(decfinal))
        print ('Monthly tax is: R', Decimal(final/12).quantize(Decimal('.01')))
        print ('You net salary per month is therefore: ', (tinc/12 - payable),
                 'or',(tinc - payable*12),'per year')
    
    def enter_another():
        print ("Would you like to calculate tax on another amount? (y/n) ")
        yesno = input('> ')
        if yesno.lower() == "y" or yesno.lower() == "yes":
            print ('Alright, let\'s start again\n')
            ask_choice()
            asking()
            ask_age()
            tax_calc()
            age_calc()
            enter_another()
        elif yesno.lower() == "n" or yesno.lower() == "no":
            print ('Thank you for trying out this calculator')
    
    
    ask_choice()
    asking()
    ask_age()
    tax_calc()
    age_calc()
    enter_another()
    
    input()
    


Answer: I think the global variables are causing you trouble. You have this near the
top

    
    
    tinc = 0
    #...
    rates = {}
    rates['T1'] = 0.18 * tinc
    rates['T2'] = 29808 + (.25 * (tinc - 165600))
    rates['T3'] = 53096 + (.30 * (tinc - 258750))
    rates['T4'] = 82904 + (.35 * (tinc - 358110))
    rates['T5'] = 132894 + (.38 * (tinc - 500940))
    rates['T6'] = 185205 + (.40 * (tinc - 638600))
    

This will use a value of 0 for `tinc` to set up the `rates`. However, you have
a function later where the user inputs the taxable income (in `ask_monthly` or
`ask_annual`). You will need to change the rates you use depending on the
value tinc takes.

**EDIT**

If you change this into a function and return the dictionary, you can pass
that to whichever functions use it

    
    
    def setup_rates(tinc):
        rates = {}
        rates['T1'] = 0.18 * tinc
        rates['T2'] = 29808 + (.25 * (tinc - 165600))
        rates['T3'] = 53096 + (.30 * (tinc - 258750))
        rates['T4'] = 82904 + (.35 * (tinc - 358110))
        rates['T5'] = 132894 + (.38 * (tinc - 500940))
        rates['T6'] = 185205 + (.40 * (tinc - 638600))
        return rates
    

Change `tax_calc` to takes the rates:

    
    
    def tax_calc(rates):
        #... as you were
    

and then changes your "main" function to find it out:

    
    
    asking()
    ask_age()
    rates = setup_rates(tinc)
    tax_calc(rates)
    

You can probably gradually refactor the functions to return the variables that
are currently global and use that in the next functions, removing the globals
slowly.

