Python列表的问题

时间:2013-01-17 07:22:04

标签: python python-2.7

  

可能重复:
  “Least Astonishment” in Python: The Mutable Default Argument

好的,所以我正在努力学习Python。几个学期前我有一个朋友曾参加Python课程,他给了我所有的旧任务。我有一个特别讨厌的问题,我认为应该很简单,但似乎无法弄清楚我的问题所在。看看你们的想法。

程序应该从名为grades.txt的文件中读取。这是文件:

2
John Doe
82
100
57
0
Jane Smith
91
12
45
81
0

此文件的格式为:第一行是学生人数。然后是学生的名字,然后是他们的成绩。零表示学生成绩列表的结尾。我知道,我知道......这样做并没有多大意义,但这就是这个方法。

无论如何,这是我到目前为止编写的代码....

#!/usr/bin/env python

class students():
        def __init__(self, fname='', lname='', grades=[]):
        self.firstName = fname
        self.lastName = lname
        self.gradeBook = grades

def lineCheck(lineText):
     try:
         int(lineText)
         return True
     except ValueError:
         return False

inFile = "grades.txt"
outFile = "summary.txt"

count = 0
numStudents = 0

studentList = []
check = False

with open(inFile, "r") as file: 
    for line in file:
        if(count == 0):
            numStudents = line.strip()
        else:
            lineRead = line.strip()
            check = lineCheck(lineRead)
            if(check == False):
                studentName = lineRead.split()
                fName = studentName[0]
                lName = studentName[1]
                temp = students(fName, lName)
            else:
                if(lineRead != '0'):
                    temp.gradeBook.append(lineRead)
                elif(lineRead == '0'):
                    studentList.append(temp)

        count += 1
file.close()

for student in studentList:
    print student.firstName + " " + student.lastName
    print student.gradeBook

使用此代码,我的预期输出位于最终for循环中程序的末尾。我希望看到这样的事情:

John Doe
['82', '100', '57']
Jane Smith
['91', '12', '45', '81']

然而,我得到的输出是:

John Doe
['82', '100', '57', '91', '12', '45', '81']
Jane Smith
['82', '100', '57', '91', '12', '45', '81']

我一直盯着这个太久了,我觉得这很简单。但是,由于我是蟒蛇新手并且还没有完全习惯它的所有细微差别,也许有经验丰富的眼睛的人可以挑选出这里发生的事情。我真的很感激你能给我的任何帮助。感谢。

2 个答案:

答案 0 :(得分:3)

您的实际问题是您使用[]作为默认参数。默认参数只创建一次并“附加”到函数中,因此每次创建新的学生对象时,都会重复使用相同的成绩列表。你需要这样的东西:

def __init__(..., grades=None):
    if grades is None:
        self.gradeBook = []
    else:
        self.gradeBook = grades

现在,请允许我给你一些批评。 :)

看起来您的代码中包含空格和制表符的组合;在像Python这样的语言中,空白很重要,这非常糟糕。我不知道你正在使用什么编辑器,但是你应该找到如何配置它所以按 Tab 总是插入四个空格。

其余部分相当不太重要,但它可以帮助您与其他Python程序员相处,并可能帮助您的代码更简单。


您可以在以下几个位置执行此操作:

if(check == 0):

括号是不必要的。

if check == 0:

您有以下内容:

if(lineRead != '0'):
    ...
elif(lineRead == '0'):
    ...

但其中只有一个可以是真的 - 它可以是相等也可以不相等 - 所以你也可以用elif ...替换else。但这导致双重否定(它不是!= ...),所以让我们交换分支。

if lineRead == '0':
    ...
else:
    ...

check = lineCheck(lineRead)
if(check == False):

您只使用check变量一次,因此不需要它。此外,避免直接与TrueFalse进行比较更为常见:

if not lineCheck(lineRead):

但这并不能很好地阅读。执行动作的函数最好命名为动词和函数(如此函数),它们在命名is_whatever时验证声音正常。变量,你想命名就像你用英语谈论它;你不会经常谈论“读行”,但你可能会谈论“读取行”,甚至只是“行”。

哦,Python style guide, PEP 8建议使用下划线而不是camelCase。

if not is_numeric(line):

类名通常用UppercaseCamelCase编写,并且应该是单数,因为它们描述了类的东西。 (“你有什么样的宠物?”“一只猫。”)你应该总是从object继承,或者你得到一个“老式的课堂”,它来自Python的早期并且有点这些混沌。

虽然我在这里,但对于没有名字的学生来说没有多大意义。虽然你最好离开not trying to split it into first and last

class Student(object):
    def __init__(self, name, grades=None):
        ...

现在没关系,但稍后将所有“主要”代码放在名为main的函数中然后运行它会很有帮助。这样,您可以从其他代码(例如测试)导入main,而无需立即运行所有内容。

if __name__ == '__main__':
    main()

__name__只是当前“模块”的名称,如果您使用'__main__'直接运行文件,则会将其设置为特殊字符串python file.py


经过一番挑剔的挑剔后,我最终得到了这个:

class Student(object):
    def __init__(self, name, grades=None):
        self.name = name
        if grades is None:
            self.gradebook = []
        else:
            self.gradebook = grades

def is_numeric(s):
    try:
        int(s)
        return True
    except ValueError:
        return False

def main(infile, outfile):
    count = 0
    num_students = 0

    students = []

    with open(infile, "r") as f:
        for line in f:
            line = line.strip()

            if count == 0:
                # This is the first line
                num_students = int(line)
            elif not is_numeric(line):
                # Non-numbers are names of new students
                cur_student = Student(line)
            elif line == '0':
                # Zero marks the end of a student
                students.append(cur_student)
            else:
                cur_student.gradebook.append(line)

            count += 1

    for student in students:
        print student.name
        print student.gradebook

if __name__ == '__main__':
    main("grades.txt", "summary.txt")

我做了一些上面没有提到的小事;我希望他们有意义。

  • file是内置函数的名称。 Python将允许您使用该名称,但如果您稍后尝试使用内置函数,您会感到惊讶。我将其替换为f,这是引用仅在短时间内打开的文件的常用方法。

  • 很难记住temp的含义!尽量不要给变量这样的名字。我将其更改为cur_student,其中“cur”是“当前”的常用缩写。

  • 您不需要f.close(); with块为您完成。事实上,这就是with的重点。

  • 无论发生什么事,你都会调用line.strip(),所以我把它作为循环中的第一件事。这样就可以将所有if合并为一个,这样可以更轻松地了解正在发生的事情以及何时发生。

  • 我添加了几条快速评论,因为正如您所指出的,这是一种非常奇怪的文件格式。

如果这意味着什么的话,这就更接近我的写作方式。

总是很高兴看到有人进入编程领域!希望你喜欢Python:)

答案 1 :(得分:2)

使用

class students():
    def __init__(self, fname='', lname='', grades=None):
        self.firstName = fname
        self.lastName = lname
        self.gradeBook = [] if grades is None else grades

问题是默认参数[]