如何在列表中更改传入for循环的变量

2024-04-19 07:06:29 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在用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循环的特定变量分配一个grade point值。所以,当score1通过for循环,并且确定了适当的分数点时,我如何才能将该分数点实际分配给score1,然后在score2等通过循环时分配给它们?

我希望这能澄清这个问题。Python不具备这种能力似乎很傻,因为如果没有,那么如果它是正在传递的列表的一部分,那么就无法重新定义通过for循环传递的任何变量。


Tags: and用户in程序for数字num分数
3条回答

问题是当你写这篇文章时:

for num in [score1, score2, score3, score4, score5]:

正在发生的是,您正在创建一个列表,其中包含五个元素,这些元素在开始迭代时由score1到score 5的值定义。更改这些元素之一不会更改原始变量,因为您已经创建了一个包含这些值副本的列表。

如果运行以下脚本:

score1 = 2
score2 = 3

for num in [score1, score2]:
    num = 1

for num in [score1, score2]:
    print(num)

您将看到,更改包含实际变量副本的列表中的每个值实际上不会更改原始变量的值。为了更好地理解这一点,您可以考虑查找“按引用传递”和“按值传递”之间的区别。

对于这个特殊的问题,我建议您首先将要修改的变量放在一个列表中,然后遍历该列表,而不是一个包含这些变量副本的列表。

“如果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

这仍然是一种非功能性的做事方式,因此容易产生所有副作用引起的问题。

第一条规则:在处理一堆类似的项时,不要使用一堆命名变量-使用数组(list、set、dictionary,任何最有意义的)。

第二条规则:除非你真的需要空间,不要用这种方式覆盖你的变量-你试图让一个标签(变量名)代表两个不同的东西(原始标记和/或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()

相关问题 更多 >