我试图在下图中的等级类别之间进行映射。然后我希望能够调用一个函数,将等级转换为等效格式的相同等级。例如:
def convert(num, letter, gpa):
"""Converts a grade into an equivalent grade. The desired output will be
specified by -1 and the grade format not to be involved in the conversion
will be specified by None. When converting to GPA, the minimum of the gpa
range will be returned."""
>>> convert(83, None, -1)
>>> 'A-'
>>>convert(-1, 'B+', None)
>>>77
我想为等价创建三个并行列表,然后函数最终会使用一堆if语句。最好的方法是什么?
答案 0 :(得分:4)
我可能会做这样的事情,它避免了条件分支,并且很清楚你在转换时想要做什么。
class GradeRange:
def __init__(self, pct, ltr, gpa):
self.pct = pct
self.ltr = ltr
self.gpa = gpa
class GradeTable:
def __init__(self):
self.ranges = [
GradeRange(range(0, 50), 'F', 0.0),
GradeRange(range(50, 53), 'D-', 0.7),
GradeRange(range(53, 57), 'D', 1.0),
GradeRange(range(57, 60), 'D+', 1.3),
GradeRange(range(60, 63), 'C-', 1.7),
GradeRange(range(63, 67), 'C', 2.0),
GradeRange(range(67, 70), 'C+', 2.3),
GradeRange(range(70, 73), 'B-', 2.7),
GradeRange(range(73, 77), 'B', 3.0),
GradeRange(range(77, 80), 'B+', 3.3),
GradeRange(range(80, 85), 'A-', 3.7),
GradeRange(range(85, 90), 'A', 4.0),
GradeRange(range(90, 101), 'A+', 4.0),
]
def convert_pct(self, pct):
for r in self.ranges:
if pct in r.pct:
return r.ltr, r.gpa
def convert_ltr(self, ltr):
for r in self.ranges:
if r.ltr == ltr:
return r.pct[0], r.gpa
def convert_gpa(self, gpa):
for r in self.ranges:
if r.gpa == gpa:
return r.pct[0], r.ltr
答案 1 :(得分:2)
你可以把它作为结果的枚举
from enum import Enum
class GradeResults(Enum):
A_PLUS = ("A+", 4.3, range(90, 101))
A = ("A", 4.0, range(85, 90))
A_MINUS = ("A-", 3.7, range(80, 85))
# etc
@classmethod
def from_lettergrade(cls, lett):
for gr in cls:
if lett == gr.lettergrade:
return gr
raise ValueError("Invalid letter grade.")
@classmethod
def from_gpa(cls, gpa):
for gr in cls:
if gpa == gr.gpa:
return gr
raise ValueError("Invalid GPA.")
@classmethod
def from_percentage(cls, pct):
for gr in cls:
if pct in gr.percentage:
return gr
raise ValueError("Percentage out of range.")
@property
def lettergrade(self):
return self.value[0]
@property
def gpa(self):
return self.value[1]
@property
def percentage(self):
return self.value[2]
这可以让您执行以下操作:
result = GradeResults.from_gpa(4.0)
# result is now GradeResults.A
result.percentage
# range(85, 90)
class_grades = [GradeResults.from_percentage(pct).lettergrade
for pct in some_existing_list_of_class_percentages]
当然:
an_a_plus = GradeResults["A_PLUS"] # or GradeResults.A_PLUS
a_c_minus = GradeResults.C_MINUS
a_c_minus == an_a_plus # False
你甚至可以玩元组的顺序((GPA, letter grade, then range)
可能效果最好)并继承enum.OrderedEnum
你可以这样做:
a_c_minus < an_a_plus # True
答案 2 :(得分:1)
只是一个建议:
grades = (
((90, 100), 'A+', 4.0),
((85, 89), 'A', 4.0),
((80, 84), 'A-', 3.7),
((77, 79), 'B+', 3.3),
((73, 76), 'B', 3.0),
((70, 72), 'B-', 2.7),
((67, 69), 'C+', 2.3),
((63, 66), 'C', 2.0),
((60, 62), 'C-', 1.7),
((57, 59), 'D+', 1.3),
((53, 56), 'D', 1.0),
((50, 52), 'D-', 0.7),
((0, 49), 'F', 0.0))
def convert(num=None, letter=None, gpa=None):
for scores, alpha, number in grades:
low, high = scores
if (
(num is None or low <= num <= high) and
(letter is None or letter == alpha) and
(gpa is None or gpa >= number)): break
else:
return 'No match'
return scores, alpha, number
convert(num = 83)
>> ((80, 84), 'A-', 3.7)
convert(letter = 'B+')
>> ((77, 79), 'B+', 3.3)