如何更改以列表形式输入 for 循环的变量

Posted

技术标签:

【中文标题】如何更改以列表形式输入 for 循环的变量【英文标题】:How to change variables fed into a for loop in list form 【发布时间】:2012-04-15 13:36:30 【问题描述】:

我正在用 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 循环传递的任何变量,如果它是正在传递的列表的一部分。

【问题讨论】:

“Python 没有这种能力似乎很愚蠢,因为如果没有这种能力,你将无法重新定义通过 for 循环传递的任何变量,如果它是正在传递的列表。” - 这就是大多数编程语言的工作方式。允许这种能力是不好的,因为它会产生一种叫做副作用的东西,这会使代码变得迟钝。 【参考方案1】:

“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

这仍然是一种非功能性的做事方式,因此容易出现副作用导致的所有问题。

【讨论】:

感谢所有建议,我想我明白你所说的关于使代码变得迟钝的意思。我觉得这很有趣,我可以看到这会如何导致一些意想不到的错误,尽管我很想知道确切的原因。另一方面,我实际上是在寻找重新定义变量而不是修改它们或像曲线一样引起全局变化,你的帖子很好地概述了如何去做。谢谢 @DustinBurns:副作用会导致意外错误,因为除非它们是受控的副作用,否则您将失去模块化代码的能力。调用具有副作用的函数是不好的,因为它不仅仅是“返回”一个值。因此,您不能轻松地测试具有副作用的函数。两次调用具有副作用的函数可能不会返回相同的值;输出可能取决于函数外部存在的数据。它使大量代码变得一团糟。【参考方案2】:

问题是当你写这个时:

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)

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

对于这个特定问题,我建议将您希望能够修改的变量放在一个列表中开始,然后遍历该列表而不是包含这些变量副本的列表。

【讨论】:

是的。我知道当 for 循环启动并调用这些特定值时,它将从 for 循环外部提取这些值,因此重新启动循环时内部更改将无效。出于这个原因,在循环之外定义列表会更容易,因此您可以在发送值之前修改循环之外的列表。不过我很好奇,如果您知道修改列表的内容,然后将这些新值返回给主函数/代码主体。这不是我想要做的,但我想知道你能不能做到【参考方案3】:
# 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

【讨论】:

我只是想知道您是否可以将这样的转换直接放入 for 循环中,而不必编写另一个函数来进行单独的转换。这个选项可以正常工作,我只是好奇在编写 for 循环时我的限制是什么。非常感谢:) 我认为,我不会这样做,而是将平均值转换为上面列出的 GPA。因此,当我取分数列表的平均值时,我会在取平均值的函数中将其转换为 GPA。 是的,无论哪种方式都有效。有时,分解所有内容可能是个好主意。根据您的需要。【参考方案4】:

第一条规则:在处理一堆相似的项目时,不要使用一堆命名变量 - 使用数组(列表、集合、字典,任何最有意义的东西)。

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

【讨论】:

抱歉,我对此有点陌生。非常感谢您的建议。我很好奇,我会尝试自己查找它,但是当您定义平均值(ls)时,您从哪里提取该变量。 ls 是否仅表示预定义列表中的所有值?如果是这样,那将是有道理的。再次感谢您的帮助! 哦,等等,我知道你在那里做了什么。您稍后在 main 中调用了该函数并将 ls 放入定义的函数中,这样您就不会限制您能够推送到该函数中的变量。酷。

以上是关于如何更改以列表形式输入 for 循环的变量的主要内容,如果未能解决你的问题,请参考以下文章

循环语句脚本

我如何在 for 循环外使用 for 循环范围变量形式?

如何在循环中更改php变量名?

如何使用for循环将返回值分配给变量

shell脚本--------for循环

Linux shell 编程:循环结构