我正在用Python编写一个基本程序,提示用户输入5个测试分数。然后程序将每个测试分数转换为分数点(即4.0,3.0,2.0 ......),然后取这些数字的平均值。
我已经为每个测试分数分配了他们自己的变量,我将它们送入for循环,如下所示:
for num in [score1, score2, score3, score4, score5]:
if num >= 90
print('Your test score is a 4.0)
elif num < 90 and >= 80
.
.
and so on for each grade point.
现在,这可以很好地显示每个测试分数等同于分数点。但是,稍后在函数中我需要计算每个等级点值的平均值。所以,我实际上想要将等级点值分配给当时通过for循环传递的特定变量。因此,当score1通过for循环并且确定了适当的成绩点时,我如何才能将该成绩点实际分配给score1,然后将其分配给score2,等等,当它们通过循环时?
我希望这会使问题清楚。 Python没有这种能力似乎很愚蠢,因为如果不是这样你将无法重新定义通过for循环传递的任何变量,如果它是正在传递的列表的一部分。
答案 0 :(得分:12)
“Python似乎没有这种能力似乎很愚蠢,因为如果不是你将无法重新定义通过for循环传递的任何变量,如果它是传递的列表的一部分通过。“ - 这就是大多数编程语言的工作方式。允许这种能力会很糟糕,因为它会产生一种称为副作用的东西,这会使代码变得迟钝。
此外,这是一个常见的编程缺陷,因为你应该保持数据不受变量名称的影响:请参阅http://nedbatchelder.com/blog/201112/keep_data_out_of_your_variable_names.html(尤其是类似问题的列表;即使您没有处理变量名字,你至少试图处理变量名称空间)。补救措施是在“更高一级”工作:在这种情况下的列表或集合。这就是你原来的问题不合理的原因。 (某些版本的python会让你破解locals()
字典,但是这是不受支持的,没有文档记录的行为和非常差的样式。)
但是你可以强迫python使用这样的副作用:
scores = [99.1, 78.3, etc.]
for i,score in enumerate(scores):
scores[i] = int(score)
以上将在scores
数组中向下舍入得分。然而,正确的方法(除非您正在处理数亿个元素)是重新创建scores
数组,如下所示:
scores = [...]
roundedScores = [int(score) for score in scores]
如果你想对分数做很多事情:
scores = [..., ..., ...]
def processScores(scores):
'''Grades on a curve, where top score = 100%'''
theTopScore = max(scores)
def processScore(score, topScore):
return 100-topScore+score
newScores = [processScore(s,theTopScore) for s in scores]
return newScores
旁注:如果你正在进行浮点计算,你应该from __future__ import division
或使用python3,或明确地转换为float(...)
。
如果你真的想修改传入的内容,可以传入一个可变对象。您传入的数字是不可变对象的实例,但例如,如果您有:
class Score(object):
def __init__(self, points):
self.points = points
def __repr__(self):
return 'Score({})'.format(self.points)
scores = [Score(i) for i in [99.1, 78.3, ...]]
for s in scores:
s.points += 5 # adds 5 points to each score
这仍然是一种非功能性的做事方式,因此容易产生副作用引起的所有问题。
答案 1 :(得分:2)
问题是当你写这个:
for num in [score1, score2, score3, score4, score5]:
发生的事情是您正在创建一个列表,其中包含五个元素,这些元素在您开始迭代时由score1到score5的值定义。更改其中一个元素不会更改原始变量,因为您已创建包含这些值副本的列表。
如果您运行以下脚本:
score1 = 2
score2 = 3
for num in [score1, score2]:
num = 1
for num in [score1, score2]:
print(num)
您将看到更改包含实际变量副本的列表中的每个值实际上并不会更改原始变量的值。为了更好地理解这一点,您可以考虑查找“按引用传递”和“按值传递”之间的区别。
对于这个特殊问题,我建议将您希望能够修改的变量放在列表中,然后迭代该列表而不是包含这些变量副本的列表。
答案 2 :(得分:2)
# Take the list of grade as input, assume list is not empty
def convertGrade(myGrades):
myResult = [] # List that store the new grade
for grade in myGrades:
gpa = (grade / 20) -1
# Depending on how many deciaml you want
gpa = round(gpa, 1)
myResult.append(gpa)
return myResult
# The list of grades, can be more than 5 if you want to
grades = [88.3, 93.6, 50.2, 70.2, 80.5]
convertedGrades = convertGrade(grades)
print(convertedGrades)
total = 0
# If you want the average of them
for grade in convertedGrades:
total += grade # add each grade into the total
average = total / len(convertedGrades)
print('Average GPA is:', average)
我认为这可能会做你想要的,这种事情很简单,所以python会期望你自己写,我不知道你是不是意味着python应该带有GPA转换器功能,你肯定可以写一个容易。如果你只想要整数,(我不确定,因为GPA通常带有小数点),那么你可以使用int(),或者在你追加之前将它四舍五入为0。
输出:
[3.4, 3.7, 1.5, 2.5, 3.0]
Average GPA is: 2.82
答案 3 :(得分:2)
第一条规则:当处理一堆类似的项目时,不使用一堆命名变量 - 使用数组(列表,集合,字典,最有意义的东西)。< / p>
第二条规则:除非你真的要求空间,否则不以这种方式覆盖你的变量 - 你试图让一个标签(变量名)代表两种不同的东西(原始标记)和/或gpa)。这使得调试真的很讨厌。
def get_marks():
marks = []
while True:
inp = raw_input("Type in the next mark (just hit <Enter> to quit): ")
try:
marks.append(float(inp))
except ValueError:
return marks
def gpa(mark):
if mark >= 90.0:
return 4.0
elif mark >= 80.0:
return 3.0
elif mark >= 70.0:
return 2.0
elif mark >= 60.0:
return 1.0
else:
return 0.0
def average(ls):
return sum(ls)/len(ls)
def main():
marks = get_marks()
grades = [gpa(mark) for mark in marks]
print("Average mark is {}".format(average(marks)))
print("Average grade is {}".format(average(grades)))
if __name__=="__main__":
main()