val*_*age 1 python conditional for-loop function python-3.x
因此,我正在通过Wentworth等人如何像计算机科学家一样思考 Python 3指南,尝试更多地学习编程.虽然它是一个很棒的资源,但它对于在Python 3中编写的样式和"最佳实践"几乎没有什么可说的.
我正在编写有关条件的章节中的一个练习题,它要求我编写一个函数,当输入int或float'mark'时返回字符串'grade'.
我这里的直接问题是关于函数中条件的重复和函数返回的值.是否有可能以某种方式使用循环使其更简洁,而不是elif一遍又一遍地编写语句?此外,main grade函数返回null None值; 我怎样才能使这个功能"富有成效"而不是None在它被称为时打印?
这是我写的:
def grade(mark):
grds = ['First','Upper Second','Second','Third','F1 Supp.','F2','F3']
if mark >= 75.0:
print("Your grade is",grds[0])
elif mark < 75.0 and mark >= 70.0:
print("Your grade is",grds[1])
elif mark < 70.0 and mark >= 60.0:
print("Your grade is",grds[2])
elif mark < 60.0 and mark >= 50.0:
print("Your grade is",grds[3])
elif mark < 50.0 and mark >= 45.0:
print("Your grade is",grds[4])
elif mark < 45.0 and mark >= 40.0:
print("Your grade is",grds[5])
elif mark < 40.0:
print("Your grade is",grds[6])
def finalmark():
mark = float(input("Enter your mark"))
fnlmark = grade(mark)
return fnlmark
print(finalmark())
Run Code Online (Sandbox Code Playgroud)
Mar*_*ers 11
不是print()在grade()函数中使用,而是返回结果并让调用者打印结果标记.该grade()功能仅用于返回成绩:
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()
Run Code Online (Sandbox Code Playgroud)
注意,finalmark()现在负责打印; 这是最好的地方,因为同样的功能也负责在屏幕上打印问题并接受用户输入.与您的版本一样,finalmark()返回None(因为这是默认值),并且我print()从finalmark()调用周围删除了以避免打印该返回值.打印它是没有意义的,finalmark()除了之外永远不会返回任何东西None.
您也可以删除一半的测试; 只挑选第一个匹配 if或elif分支,其余部分被跳过.因此,您可以删除先前分支已涵盖的测试:
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]
Run Code Online (Sandbox Code Playgroud)
如果第一次if mark >= 75.0:测试不匹配,则不再需要测试mark < 75.0,因为我们已经测试了反向测试.测试对于mark >= 70.0下一年级来说已经足够了.如果不匹配,我们知道标记肯定小于70,所以下一个测试只需要测试它是否大于60.0等等.
现在出现了一种可以构建循环的模式.您测试下限,如果匹配,则知道要返回哪个索引.构建一个单独的列表来存储下限:
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]
Run Code Online (Sandbox Code Playgroud)
我使用这里的zip()函数来配对成绩名称和边界,成对.您也可以使用该enumerate()函数生成索引以及每个成绩名称或for index in range(len(grds)):循环,但我发现zip()在这里工作更清洁.
接下来,我们可以开始聪明地使用算法.以上仍然逐一测试每个等级,从高到低.对于N个等级,这可能需要N个步骤.这是一个线性算法,它需要与输入一样多的步骤.
但是等级是分类的,所以我们可以在这里使用二分; 跳到中间,看看标记是低于还是高于当前界限.然后选择一半,再次测试,直到找到最佳匹配.Bisection最多采用Log(N)步.Python包含非常快速的实现 ; 它假定值按递增顺序排列,因此反转等级和边界:
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)]
Run Code Online (Sandbox Code Playgroud)
bisect.bisect_right()一分为二bounds,找到"插入点" mark,它将位于列表中相同值的右侧.因此,35.0将插入at 0,50.0at 3(等于或更高),74.0at 5和at 75.0或更高处6.而那些恰好是匹配等级的确切指数.