<p>与其在<code>grade()</code>函数中使用<code>print()</code>,<em>返回结果并让调用者打印结果标记。<code>grade()</code>函数只能用于返回等级:</p>
<pre><code>def grade(mark):
grds = ['First','Upper Second','Second','Third','F1 Supp.','F2','F3']
if mark >= 75.0:
return grds[0]
# .. etc
def finalmark():
mark = float(input("Enter your mark"))
fnlmark = grade(mark)
print("Your grade is", fnlmark)
finalmark()
</code></pre>
<p>请注意,<code>finalmark()</code>现在负责打印;这是它的最佳位置,因为同样的函数也负责在屏幕上打印问题并接受用户输入。与您的版本一样,<code>finalmark()</code>返回<code>None</code>(因为这是默认值),我从<code>finalmark()</code>调用中删除了<code>print()</code>,以避免打印返回值。打印它没有任何意义,<code>finalmark()</code>将永远不会返回除<code>None</code>之外的任何内容。你知道吗</p>
<p>您还可以删除一半的测试;只有<em>第一个匹配的</em><code>if</code>或<code>elif</code>分支被选中,其余的被跳过。因此,您可以删除以前的分支已覆盖的测试:</p>
<pre><code>def grade(mark):
grds = ['First','Upper Second','Second','Third','F1 Supp.','F2','F3']
if mark >= 75.0:
return grds[0]
elif mark >= 70.0:
return grds[1]
elif mark >= 60.0:
return grds[2]
elif mark >= 50.0:
return grds[3]
elif mark >= 45.0:
return grds[4]
elif mark >= 40.0:
return grds[5]
else:
return grds[6]
</code></pre>
<p>如果第一个<code>if mark >= 75.0:</code>测试不匹配,那么就不需要再测试<code>mark < 75.0</code>,因为我们已经测试了反向的</em>。对下一个年级来说,测试<code>mark >= 70.0</code>就足够了。如果不匹配,我们知道标记肯定小于70,所以下一个测试只需要测试它是否大于<code>60.0</code>,等等</p>
<p>现在出现了一个模式,你可以在上面建立一个循环。测试<em>下限</em>,如果它匹配,就知道要返回哪个索引。建立一个单独的列表来存储下限:</p>
<pre><code>def grade(mark):
grds = ['First','Upper Second','Second','Third','F1 Supp.','F2','F3']
bounds = [75.0, 70.0, 60.0, 50.0, 45.0, 40.0]
for grade, bound in zip(grds, bounds):
if mark >= bound:
return grade
# there is no lower bound for F3; if the loop didn't find a match,
# we end up here and can assume the lowest grade.
return grds[6]
</code></pre>
<p>我用这里的<a href="https://docs.python.org/3/library/functions.html#zip" rel="nofollow noreferrer">^{<cd17>} function</a>将等级名称和界限成对排列。您也可以使用<a href="https://docs.python.org/3/library/functions.html#enumerate" rel="nofollow noreferrer">^{<cd18>} function</a>来生成一个索引以及每个年级名称,或者一个<code>for index in range(len(grds)):</code>循环,但是我发现<code>zip()</code>在这里更有效。你知道吗</p>
<p>下一步,我们可以开始聪明的算法。以上仍然测试每个年级,从高到低,一个接一个。对于N个等级,最多需要N个步骤。这是一个<em>线性算法</em>,它需要的步骤和输入的步骤一样多。你知道吗</p>
<p>但是等级是排序的,所以我们可以在这里使用二等分;跳到中间看看分数是低于还是高于当前界限。然后选择其中的一半,再次测试,直到找到最佳匹配。对分最多需要对数(N)步。Python有一个<a href="https://docs.python.org/3/library/bisect.html" rel="nofollow noreferrer">very fast implementation included</a>;它假定值按<em>递增</em>的顺序递增,因此反转等级和边界:</p>
<pre><code>import bisect
def grade(mark):
grds = ['F3', 'F2', 'F1 Supp.', 'Third', 'Second', 'Upper Second', 'First']
bounds = [40.0, 45.0, 50.0, 60.0, 70.0, 75.0]
return grds[bisect.bisect_right(bounds, mark)]
</code></pre>
<p><code>bisect.bisect_right()</code>平分成<code>bounds</code>以找到<code>mark</code>的“插入点”,它将位于列表中相同值的右侧<em>。所以<code>35.0</code>会被插入<code>0</code>,<code>50.0</code>会被插入<code>3</code>(因为它等于或高于<em></em>),<code>74.0</code>会被插入<code>5</code>,任何东西都会被插入<code>75.0</code>或更高的<code>6</code>。这些恰好是匹配等级的准确指标。你知道吗</p>