如何简化评分系统函数中重复的 if-elif 语句?

Mat*_*res 20 python if-statement dry

目标是构建一个程序,将分数从“0 到 1”系统转换为“F 到 A”系统:

  • 如果score >= 0.9会打印“A”
  • 如果score >= 0.8会打印'B'
  • 0.7,C
  • 0.6, D
  • 以及低于该点的任何值,打印 F

这是构建它的方法,它适用于程序,但有点重复:

if scr >= 0.9:
    print('A')
elif scr >= 0.8:
    print('B')
elif scr >= 0.7:
    print('C')
elif scr >= 0.6:
    print('D')
else:
    print('F')
Run Code Online (Sandbox Code Playgroud)

我想知道是否有一种方法可以构建一个函数,以便复合语句不会重复。

我是一个完全的初学者,但会在以下几行:

def convertgrade(scr, numgrd, ltrgrd):
    if scr >= numgrd:
        return ltrgrd
    if scr < numgrd:
        return ltrgrd
Run Code Online (Sandbox Code Playgroud)

可能吗?

这里的意图是稍后我们可以通过只传递 scr、numbergrade 和 letter grade 作为参数来调用它:

convertgrade(scr, 0.9, 'A')
convertgrade(scr, 0.8, 'B')
convertgrade(scr, 0.7, 'C')
convertgrade(scr, 0.6, 'D')
convertgrade(scr, 0.6, 'F')
Run Code Online (Sandbox Code Playgroud)

如果可以传递更少的参数,那就更好了。

daw*_*awg 34

您可以使用bisect模块进行数字表查找:

from bisect import bisect 

def grade(score, breakpoints=[60, 70, 80, 90], grades='FDCBA'):
     i = bisect(breakpoints, score)
     return grades[i]

>>> [grade(score) for score in [33, 99, 77, 70, 89, 90, 100]]
['F', 'A', 'C', 'C', 'B', 'A', 'A']
Run Code Online (Sandbox Code Playgroud)

  • @norok2 我不认为 4 个元素的列表是开始的地方。对于如此小的列表,线性扫描可能会更快。再加上使用可变的默认参数,无需任何注意;) (4认同)
  • 我想为“bisect”的使用额外+1,我发现它很少使用。 (2认同)
  • 这是二分模块的示例 (2认同)

sch*_*ggl 12

您可以按照以下方式做一些事情:

# if used repeatedly, it's better to declare outside of function and reuse
# grades = list(zip('ABCD', (.9, .8, .7, .6)))

def grade(score):
    grades = zip('ABCD', (.9, .8, .7, .6))
    return next((grade for grade, limit in grades if score >= limit), 'F')

>>> grade(1)
'A'
>>> grade(0.85)
'B'
>>> grade(0.55)
'F'
Run Code Online (Sandbox Code Playgroud)

next与生成器上的默认参数一起使用创建的分数-等级对zip。它实际上与您的循环方法完全等效。


小智 6

您可以为每个等级分配一个阈值:

grades = {"A": 0.9, "B": 0.8, "C": 0.7, "D": 0.6, "E": 0.5}

def convert_grade(scr):
    for ltrgrd, numgrd in grades.items():
        if scr >= numgrd:
            return ltrgrd
    return "F"
Run Code Online (Sandbox Code Playgroud)

  • 请注意,如果您使用的是 Python 3.6 或更低版本,则应该执行“sorted(grades.items())”,因为不能保证字典已排序。 (2认同)
  • 当然不是最有效的,但它可以说是最具可读性的,因为所有标记都写得接近其阈值。我宁愿建议用成对的元组替换字典。 (2认同)

Ric*_*cco 5

在这种特定情况下,您不需要外部模块或生成器。一些基本的数学就足够了(而且更快)!

grades = ["A", "B", "C", "D", "F"]

def convert_score(score):
    return grades[-max(int(score * 10) - 5, 0) - 1]

# Examples:
print(convert_grade(0.61)) # "D"
print(convert_grade(0.37)) # "F"
print(convert_grade(0.94)) # "A"

Run Code Online (Sandbox Code Playgroud)