Функция проверки входных данных Python с сохранением старых переменных

#python #python-3.x #validation #for-loop

Вопрос:

В настоящее время я пишу налоговый калькулятор, и я заметил, что если я ввожу неверный налоговый код, то сначала кажется, что он отклоняется, но затем программа, похоже, сохраняет исходные данные и просматривает их в обратном порядке (вот так).:

 [User Input] Gross Income: £32,000
[User Input] Tax Code: 32,000
Tax Code after input: 32,000
Failed letter check
Invalid input. Please enter your tax code.
[User Input] Tax Code: y      
Tax Code after input: y
Passed letter check
Tax Code after letter check: y
Tax Code during dictionary match check (false): y
Failed dictionary match check
Invalid input. Please enter your tax code.       
[User Input] Tax Code: 1257L  
Tax Code after input: 1257L
Passed letter check
Tax Code after letter check: 1257L
Tax Code during dictionary match check (true): 1257L
Passed dictionary match check
Tax Code after dictionary match check: 1257L
Personal Allowance: 12570
Tax Letter: L
Tax Code after dictionary match check: y
Personal Allowance: 0
Tax Letter: Y
Tax Code after letter check: 32,000
Traceback (most recent call last):
  File "C:UsersJoshua.RiberioGittaxcalctaxcalc.py", line 336, in <module>   
    salarycalc()
  File "C:UsersJoshua.RiberioGittaxcalctaxcalc.py", line 243, in salarycalc 
    personal_allowance, tax_letter = get_tax_code()
  File "C:UsersJoshua.RiberioGittaxcalctaxcalc.py", line 78, in get_tax_code
    tax_letter = tax_code[tax_letter_index:].upper()
TypeError: slice indices must be integers or None or have an __index__ method
 

Вот мой код:

 def get_tax_code():
    tax_code = input('Tax Code: ')
    print('Tax Code after input:', tax_code)
    tax_letter_index = ''
    # Checking input contains a letter
    for char in tax_code:
        if char.upper() in alpha:
            tax_letter_index = tax_code.index(char)
            print('Passed letter check')
            break
    
    if tax_letter_index == '':
        print('Failed letter check')
        print('Invalid input. Please enter your tax code.')
        get_tax_code()

    print('Tax Code after letter check:', tax_code)

    tax_letter = tax_code[tax_letter_index:].upper()

    # Checking input has a key match in the tax_letters dictionary
    if tax_letter not in tax_letters.keys():
        print('Tax Code during dictionary match check (false):', tax_code)
        print('Failed dictionary match check')
        print('Invalid input. Please enter your tax code.')
        get_tax_code()
    elif tax_letter in tax_letters.keys():
        print('Tax Code during dictionary match check (true):', tax_code)
        print('Passed dictionary match check')
        
    print('Tax Code after dictionary match check:', tax_code)

    # Getting personal allowance from Tax Code
    personal_allowance = tax_code[:tax_letter_index]
    if personal_allowance == '':
        personal_allowance = 0
    else:
        personal_allowance = int(personal_allowance) * 10

    # Setting personal allowance exceptions for gross income over £100,000
    if gross_income > 100000:
        personal_allowance = set_personal_allowance - ((gross_income - 100000) / 2)
        if personal_allowance < 0:
            personal_allowance = 0
            
    print('Personal Allowance:', personal_allowance)
    print('Tax Letter:', tax_letter)
    
    return personal_allowance, tax_letter
 

The excessive prints are just so I could see where the input was being changed. It seems as though after a successful run through, the code loops back up to the top using the previous invalid inputs, resulting in the code failing to run.

Can anybody see where I’m going wrong?

Notes

tax_letters является определенным словарем, будет обновлять его для извлечения из выбранного CSV:

 tax_letters = {
    "L": "You’re entitled to the standard tax-free Personal Allowance",
    "M": "Marriage Allowance: you’ve received a transfer of 10% of your partner’s Personal Allowance",
    "N": "Marriage Allowance: you’ve transferred 10% of your Personal Allowance to your partner",
    "T": "Your tax code includes other calculations to work out your Personal Allowance",
    "0T": "Your Personal Allowance has been used up, or you’ve started a new job and your employer does not have the details they need to give you a tax code",
    "BR": "All your income from this job or pension is taxed at the basic rate (usually used if you’ve got more than one job or pension)",
    "D0": "All your income from this job or pension is taxed at the higher rate (usually used if you’ve got more than one job or pension)",
    "D1": "All your income from this job or pension is taxed at the additional rate (usually used if you’ve got more than one job or pension)",
    "NT": "You’re not paying any tax on this income",
    "S": "Your income or pension is taxed using the rates in Scotland",
    "S0T": "Your Personal Allowance (Scotland) has been used up, or you’ve started a new job and your employer does not have the details they need to give you a tax code",
    "SBR": "All your income from this job or pension is taxed at the basic rate in Scotland (usually used if you’ve got more than one job or pension)",
    "SD0": "All your income from this job or pension is taxed at the intermediate rate in Scotland (usually used if you’ve got more than one job or pension)",
    "SD1": "All your income from this job or pension is taxed at the higher rate in Scotland (usually used if you’ve got more than one job or pension)",
    "SD2": "All your income from this job or pension is taxed at the top rate in Scotland (usually used if you’ve got more than one job or pension)",
    "C": "Your income or pension is taxed using the rates in Wales",
    "C0T": "Your Personal Allowance (Wales) has been used up, or you’ve started a new job and your employer does not have the details they need to give you a tax code",
    "CBR": "All your income from this job or pension is taxed at the basic rate in Wales (usually used if you’ve got more than one job or pension)",
    "CD0": "All your income from this job or pension is taxed at the higher rate in Wales (usually used if you’ve got more than one job or pension)",
    "CD1": "All your income from this job or pension is taxed at the additional rate in Wales (usually used if you’ve got more than one job or pension)"
    }
 

gross_income определяется в основной функции:

 def salarycalc():
    screen_clear()

    global gross_income
    gross_income = input('Gross Income: £')

    if ',' in gross_income:
        gross_income = gross_income.replace(',', '')

    if '£' in gross_income:
        gross_income = gross_income.replace('£', '')

    gross_income = float(gross_income)
 

set_personal_allowance является переменной, определяемой значением в словаре «tax_brackets», снова обновит это позже, чтобы извлечь из выборки CSV:

 tax_brackets = {
    'Personal Allowance': 12570,
    'Basic': [0, 0.2],
    'Higher': [50270, 0.4],
    'Additional': [150000, 0.45]
}

set_personal_allowance = tax_brackets['Personal Allowance']
 

Комментарии:

1. Где находится tax_letters gross_income и set_personal_allowance определено?

2. @vnk Я только что добавил примечание, чтобы прояснить это, спасибо, что посмотрели

3. ваша проблема в том, что внутри get_tax_code() вы снова запускаетесь get_tax_code() — поэтому, закончив вторую get_tax_code() , она возвращается к первой get_tax_code() и продолжает ее. Вы должны, по крайней мере, использовать return после выполнения (каждую) секунду get_tax_code() — и он также выйдет первым get_tax_code() , не продолжая его.

Ответ №1:

Таким образом, основная причина, по которой ваш код, вероятно, не работал, заключалась в повторяющихся рекурсивных вызовах. Чтобы упростить подход, я разбил необходимые функции на 2 проверочные проверки. Пожалуйста, обратите внимание, что я включил несколько примеров данных для проверки программы, вы можете соответственно игнорировать это.
Функция драйвера get_tax_code работает до тех пор, пока две проверки верны, это означает, что она перестанет запрашивать ввод только после того, как налоговый код будет проверен как проверкой букв, так и соответствием словарю.

 def get_tax_code(tax_letters):
    gross_income = 32000
    set_personal_allowance = 12570
    check1 = True
    check2 = True

    while check1 or check2:
        tax_code = input('Tax Code: ')
        print('Tax Code after input:', tax_code)
        tax_letter_index = verify1(tax_code)
        if tax_letter_index != -1:
            check1 = False
            tax_letter = tax_code[tax_letter_index:].upper()
            print('Tax Code after letter check:', tax_code)
            x = verify2(tax_letter, tax_letters)
            if x:
                print('Tax Code during dictionary match check (true):', tax_code)
                print('Passed dictionary match check')
                print('Tax Code after dictionary match check:', tax_code)
                check2 = False
            else:
                print('Tax Code during dictionary match check (false):', tax_code)
                print('Failed dictionary match check')
                print('Invalid input. Please enter your tax code.')
        
        else:
            print('Failed letter check')
            print('Invalid input. Please enter your tax code.')

    
    # Getting personal allowance from Tax Code
    personal_allowance = tax_code[:tax_letter_index]
    if personal_allowance == '':
        personal_allowance = 0
    else:
        personal_allowance = int(personal_allowance) * 10

    # Setting personal allowance exceptions for gross income over £100,000
    if gross_income > 100000:
        personal_allowance = set_personal_allowance - ((gross_income - 100000) / 2)
        if personal_allowance < 0:
            personal_allowance = 0
            
    print('Personal Allowance:', personal_allowance)
    print('Tax Letter:', tax_letter)
 

Это две вспомогательные функции, которые ранее были включены в get_tax_code .
Первая функция verify1() выполняет проверку букв, в то время как вторая verify2() обрабатывает соответствие словаря. Значения, возвращаемые обеими этими функциями, определяют, будут ли обновлены контрольные значения, что в свою очередь решает, должен ли пользователь снова вводить tax_code входные данные.

 def verify1(tax_code):
    tax_letter_index = ''
    # Checking input contains a letter
    for char in tax_code:
        if char.upper().isalpha():
            tax_letter_index = tax_code.index(char)
            print('Passed letter check')
            break
    if tax_letter_index == '':
        return -1
    else:
        return tax_letter_index

def verify2(tax_letter, tax_letters):
    if tax_letter not in tax_letters.keys():
        return False
    elif tax_letter in tax_letters.keys():
        return True
 

Выход

 Tax Code: 3200
Tax Code after input: 3200
Failed letter check
Invalid input. Please enter your tax code.
Tax Code: y
Tax Code after input: y
Passed letter check
Tax Code during dictionary match check (false): y
Failed dictionary match check
Invalid input. Please enter your tax code.
Tax Code: 1257L
Tax Code after input: 1257L
Passed letter check
Tax Code during dictionary match check (true): 1257L
Passed dictionary match check
Tax Code after dictionary match check: 1257L
Personal Allowance: 12570
Tax Letter: L
 

Комментарии:

1. Это именно то, что я искал, спасибо. Пометил это как ответ. Это также научило меня некоторым основам, которых мне явно не хватало. Я ценю вашу помощь

2. Пожалуйста. Рад, что это помогло.