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]