Home > Software design >  If loop with multiple conditions still executing when one condition is not met
If loop with multiple conditions still executing when one condition is not met

Time:10-18

I'm making a roman numeral to integer converter. In the code below, you will see the function math_logic. When I give the input CCC, the program should skip the if statements and elif statements (because of the keyword and) and go right to the else statement since only one of the two conditions are met. The else statement should return a dictionary value using parameter char_0 as the key. However, the program will run the code inside the second elif statement and return TypeError: unsupported operand type(s) for : 'int' and 'NoneType' as the error.

I'm not sure why this is happening. You can put a debug point at line 38 and step into 4 times to get to the issue I'm having.

Please see code below

romanToIntDictionary = {
    "I": 1,
    "V": 5,
    "X": 10,
    "L": 50,
    "C": 100,
    "D": 500,
    "M": 1000
}

subtraction_happened = [
    4,
    9,
    40,
    90,
    400,
    900
]


def convert_roman_to_int(string, checker_state):
    characters_left = len(string)
    character_list = []
    total = 0
    if checker_state:
        print("What you entered is a valid roman numeral.")
        for character in string:
            character_list.append(character)
        while characters_left > 1:
            did_i_sub = False
            for item in subtraction_happened:
                if (not did_i_sub) and (item == math_logic(character_list[0], character_list[1], romanToIntDictionary)): #the order of multiple conditions matters
                    total = total   math_logic(character_list[0], character_list[1], romanToIntDictionary)
                    characters_left -= 2
                    character_list.pop(0)
                    character_list.pop(0)
                    did_i_sub = True
            if not did_i_sub:
                total = total   math_logic(character_list[0], character_list[1], romanToIntDictionary)
                characters_left -= 1
                character_list.pop(0)
        while characters_left == 1:
            total = total   romanToIntDictionary[character_list[0]]
            characters_left -= 1
            character_list.pop(0)
        print(total)
    if not checker_state:
        print("What you entered is not a roman numeral.")


def math_logic(char_0, char_1, r_to_i_dict):
    if (char_0 == "I") and (char_1 == "V" or "X"):
        if char_1 == "V":
            return 4
        elif char_1 == "X":
            return 9
    elif (char_1 == "L" or "C") and (char_0 == "X"):
        if char_1 == "L":
            return 40
        elif char_1 == "C":
            return 90
    elif (char_1 == "D" or "M") and (char_0 == "C"):
        if char_1 == "D":
            return 400
        elif char_1 == "M":
            return 900
    else:
        return r_to_i_dict[char_0]


def roman_numeral_checker(string):
    is_roman_numeral = True
    characters_left = len(string)
    while is_roman_numeral and characters_left > 0:
        for character in string:
            if character not in romanToIntDictionary.keys():
                is_roman_numeral = False
            characters_left -= 1
    if not is_roman_numeral:
        return False
    if is_roman_numeral:
        return True


string_from_user = (input("Enter a roman numeral to convert: ")).upper()
convert_roman_to_int(string_from_user, roman_numeral_checker(string_from_user))

CodePudding user response:

The trouble is in your boolean logic:

value = 'c'

print(value == 'X' or 'V')
'V'

This is because 'V' is a "truthy" value:

bool('V')
True

So you are saying if value == 'X' or True: which will always be True. Because of this, there's an else that isn't evaluating:

if value == 'X' or 'V':
    if value == 'X':
        print('X!')
    elif value == 'V':
        print('V!')
    else:
        print('unexpected')

unexpected

The correct syntax is:

if value == 'X' or value == 'V':

Or even more succinctly:

if value in ('X', 'V'):
    if value == 'X':
        do something
    else:
        do something

The else ensures that all cases are covered, and they are, because value could only be 'X' or 'V'.

So your whole math logic function would be:

def math_logic(char_0, char_1, r_to_i_dict):
    if char_0 == "I" and char_1 in ('V', 'X'):
        if char_1 == "V":
            return 4
        else:
            return 9
    elif char_1 in ('L', 'C') and char_0 == "X":
        if char_1 == "L":
            return 40
        else:
            return 90
    elif char_1 in ('D', 'M') and char_0 == "C":
        if char_1 == "D":
            return 400
        else:
            return 900
    else:
        return r_to_i_dict[char_0]
  • Related