Home > Mobile >  Python - Function always returns the same output regardless of input, how can I fix this?
Python - Function always returns the same output regardless of input, how can I fix this?

Time:10-02

I'm writing a code which reads some information from a file into a 2D array list. I then need to use a check_records function to validate each item on the list to make sure it meets certain requirements. i.e. each item contains an id, account etc. and those need to be a certain length and format. If the items don't meet these requirements they must be removed from the list. The number of valid and invalid items is then displayed on the screen.

However, my check_records function isn't working as intended. No matter what I do or change it refuses to validate more or less than 4 items from the list. It will invalidate any remaining items regardless of how many are in the list (from file). This happens seemingly at random, as the some items classed as valid are invalid and some classed as valid are actually invalid. It's not even validating the first 4 in the list, its just a random 4 from the list.

Looks like this on the screen:

**************************
UTOPIA BANK ATM LOG VIEWER
**************************

Enter the file name (include .txt extension): ATM_Log1.txt

--Log records loaded from (ATM_Log1.txt)--

Found (4) valid records. #Correct count (8 total items on list), incorrect items validated/invalidated
Found (4) invalid records.

#Items loaded into the list (printed just to show):
[['SYD127', '12823983', 'D', '20.00'], ['BHS115', '76530902', 'B', '0.50'], ['DUB796', 
'50175864', 'W', '225.00'], ['PMQ426', '34957765', 'B', '5700.00']] 

******************
    MAIN MENU
******************

(1) Show all records
(2) Search by ATM ID
(3) Search by Account Number
(4) Search by Operation
(5) Exit
******************
Enter a choice:

Below is the section of code that I believe has the issue. While messing around will this part I have been able to get the program to accept all items as valid but not do what it's supposed to do. Changing other sections seems to have to effect on this particular issue.

    overall_valid = None 
    
    for elem in log_records:
        if not (id_valid == True and account_valid == True and operation_valid == True and 
        amount_valid == True):
            overall_valid = False

    for elem in log_records:
        if overall_valid == False:
            count  = 1
            log_records.remove(elem)          

    valid_records = len(log_records)
    invalid_records = count
    print(f"Found ({valid_records}) valid records.")
    print(f"Found ({invalid_records}) invalid records.")
    print(" ")

I have tried writing this multiple different ways and I posted previous question about another part of this code. Basically I'm at my limit of knowledge with this and I can't find a solution. Si I'm hoping that someone can give me some guidance on where I am going wrong. (I know my code isn't pretty and some stuff might be done in a weird way but I'm still learning).

The whole function for context if needed:

def check_records(log_records):   
    ID  = [i[0] for i in log_records]
    account = [i[1] for i in log_records]
    operation = [i[2] for i in log_records]
    amount = [i[3] for i in log_records]
    count = 0

    #-----------------------
    #****Validate ATM ID****
    letters = ID[0:2]
    numbers = ID[3:]
    id_valid = None

    for elem in ID:
        if len(elem) != 6:
            valid = False
    for elem in letters:
        if len(letters) != 3:
            valid = False
        if not (elem.isalpha() for letters in ID for elem in letters):
            valid = False

    for elem in numbers:
        if len(numbers) != 3:
            valid = False
        if not (elem.isalpha() for numbers in ID for elem in numbers):
            valid = False

    if valid != False:
        valid = True

    if valid == True:
        id_valid = True
    else:
        id_valid = False

    #-------------------------------
    #****Validate Account Number****
    account_valid = None

    for elem in account:
        if not elem.isdigit():
            valid = False
        #Account number must be 8 digits long. 
        if len(str(account)) != 8:
            valid = False
    #If the account number meets all requirments then it is valid.
    if valid != False:
            valid = True

    #Account number will be returned as either true or false.
    if valid == True:
        account_valid = True
    else:
        account_valid = False

    #-------------------------------
    #****Validate Operation****
    operation_valid = None

    for elem in operation:
        #Operation must be B, D or W.
        if operation != 'B' or 'D' or 'W':
            valid = False
    if valid != False:
        valid = True

    #If the operation meets all requirments then it is valid.
    if valid == True:
        operation_valid = True
    else:
        operation_valid = False

    #-------------------------------
    #****Validate Amount****
    amount_valid = None

    for elem in amount:
        #Amount must be a float number
        if amount != float:
            valid = False
        if amount == float:
            valid = True

     #If the amount meets all requirments then it is valid.
    if valid == True:
        amount_valid = True
    else:
        amount_valid = False

REST CONTINUES AS SHOWN EARLIER (PROBLEM CODE)

CodePudding user response:

Issues with posted code

  • The first obvious issue with function check_records:
    1. variable valid is not assigned before the for loop (i.e. should be True),
    2. letters are defined as the first two IDs (i.e. letters = ID[0:2]) and numbers to the remaining. Are you trying to check if the first 3 characters of each ID are numeric and the last 3 characters are letters?
  • Assigning letters to ID[0:2] is incorrect since this is just the first two IDs rather than the letters of each ID
  • if operation != 'B' or 'D' or 'W': is the incorrect multiple condition if statement for your purpose (i.e. this conditional is always True). Search stackoverflow python for multiple condition if statement
  • An option is to have Boolean lists for id_valid, amount_valid, operation_valid, amount_valid that will contain the validity of each log_record. The value will be set based on whether the corresponding log_record is valid or not

Corrections

def check_records(log_records):   
    ID  = [i[0] for i in log_records]         # ID is first field
    account = [i[1] for i in log_records]     # account second field
    operation = [i[2] for i in log_records]   # operation third field
    amount = [i[3] for i in log_records]      # amount 4th field
    
    # Boolean for validity of each field in record (initialize all to True)
    id_valid = [True for _ in range(len(log_records))]
    account_valid = [True for _ in range(len(log_records))]
    operation_valid = [True for _ in range(len(log_records))]
    amount_valid = [True for _ in range(len(log_records))]
    
    #-----------------------
    #****Validate ATM ID****
    for index, elem in enumerate(ID):
        if len(elem) != 6:
            id_valid[index] = False
        else:
            letters = elem[0:3]    # first 3 characters of current ID
            numbers = elem[3:]     # characters in ID after first 3

            if len(letters) != 3 or not letters.isalpha():
                id_valid[index] = False    
            elif len(numbers) != 3 or not numbers.isnumeric():
                id_valid[index] = False 
                
    #-------------------------------
    #****Validate Account Number****
    for index, elem in enumerate(account):
        account_valid[index] = len(elem) == 8 and elem.isnumeric()

    #-------------------------------
    #****Validate Operation****
    for index, elem in enumerate(operation):
        operation_valid[index] = elem in ["B", "D", "W"]
        

    #-------------------------------
    #****Validate Amount****
    def isfloat(num):
        ' Checks if string is float'
        try:
            float(num)
            return True
        except ValueError:
            return False
            
    for index, elem in enumerate(amount):
        amount_valid[index] = isfloat(elem)
        
    overall_valid = [(id_valid[index] and 
                      account_valid[index] and 
                      operation_valid[index] and 
                      amount_valid[index]) for index in range(len(log_records))]
    
    # Keep only valid records
    log_records = [rec for index, rec in enumerate(log_records) if overall_valid[index]]
    
    valid_records = len(log_records)
    invalid_records = len(overall_valid) - sum(overall_records) 
    print(f"Found ({valid_records}) valid records.")
    print(f"Found ({invalid_records}) invalid records.")
    print(" ")
  • Related