patternpythonMinor
Get letter grade using eval()
Viewed 0 times
gradegetusinglettereval
Problem
I understand that using eval is extremely dangerous as it can execute deadly commands as an input by the user.
I'm trying to write a code to get a letter grade from a number between 0 to 1. I was trying to write it in the most elegant way. Is this safe?
I'm trying to write a code to get a letter grade from a number between 0 to 1. I was trying to write it in the most elegant way. Is this safe?
try:
score = float(raw_input('Enter score: '))
except Exception as ex:
print 'Score must be a number!'
quit()
if score > 1:
print 'Score must be less than 1'
quit()
grades = {
'A': str(score) + '>= 0.9',
'B': str(score) + '>= 0.8',
'C': str(score) + '>= 0.7',
'D': str(score) + '>= 0.6',
'F': str(score) + '< 0.6',
}
for key in sorted(grades):
if eval(grades[key]):
print key
quit()Solution
You're right to suspect that using
You can define the values of
Now you can write a
I converted the code that just prints the key and quits to a function,
so that you can verify the correct behavior using assertions:
Actually, using a dictionary for
It could be just a list of tuples in the correct order so that you can even skip the sorting step:
eval stinks: it really does.You can define the values of
grades as tuples of functions and a parameter:def greater_than_or_equal(score, x):
return score >= x
def less_than(score, x):
return score < x
grades = {
'A': (greater_than_or_equal, 0.9),
'B': (greater_than_or_equal, 0.8),
'C': (greater_than_or_equal, 0.7),
'D': (greater_than_or_equal, 0.6),
'F': (less_than, 0.6),
}Now you can write a
get_grade function that returns the correct grade using the evaluator and a parameter:def get_grade(score):
for key in sorted(grades):
evaluator, param = grades[key]
if evaluator(score, param):
return keyI converted the code that just prints the key and quits to a function,
so that you can verify the correct behavior using assertions:
assert 'F' == get_grade(0.1)
assert 'F' == get_grade(0.5)
assert 'D' == get_grade(0.6)
assert 'D' == get_grade(0.61)
assert 'C' == get_grade(0.7)
assert 'B' == get_grade(0.8)
assert 'A' == get_grade(0.9)
assert 'A' == get_grade(0.91)
assert 'A' == get_grade(1)Actually, using a dictionary for
grades doesn't make a lot of sense.It could be just a list of tuples in the correct order so that you can even skip the sorting step:
grade_evaluators = (
(greater_than_or_equal, 0.9, 'A'),
(greater_than_or_equal, 0.8, 'B'),
(greater_than_or_equal, 0.7, 'C'),
(greater_than_or_equal, 0.6, 'D'),
(less_than, 0.6, 'F'),
)
def get_grade(score):
for evaluator, param, grade in grade_evaluators:
if evaluator(score, param):
return gradeCode Snippets
def greater_than_or_equal(score, x):
return score >= x
def less_than(score, x):
return score < x
grades = {
'A': (greater_than_or_equal, 0.9),
'B': (greater_than_or_equal, 0.8),
'C': (greater_than_or_equal, 0.7),
'D': (greater_than_or_equal, 0.6),
'F': (less_than, 0.6),
}def get_grade(score):
for key in sorted(grades):
evaluator, param = grades[key]
if evaluator(score, param):
return keyassert 'F' == get_grade(0.1)
assert 'F' == get_grade(0.5)
assert 'D' == get_grade(0.6)
assert 'D' == get_grade(0.61)
assert 'C' == get_grade(0.7)
assert 'B' == get_grade(0.8)
assert 'A' == get_grade(0.9)
assert 'A' == get_grade(0.91)
assert 'A' == get_grade(1)grade_evaluators = (
(greater_than_or_equal, 0.9, 'A'),
(greater_than_or_equal, 0.8, 'B'),
(greater_than_or_equal, 0.7, 'C'),
(greater_than_or_equal, 0.6, 'D'),
(less_than, 0.6, 'F'),
)
def get_grade(score):
for evaluator, param, grade in grade_evaluators:
if evaluator(score, param):
return gradeContext
StackExchange Code Review Q#82243, answer score: 4
Revisions (0)
No revisions yet.