可能重复:
“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']
我一直盯着这个太久了,我觉得这很简单。但是,由于我是蟒蛇新手并且还没有完全习惯它的所有细微差别,也许有经验丰富的眼睛的人可以挑选出这里发生的事情。我真的很感激你能给我的任何帮助。感谢。
答案 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
变量一次,因此不需要它。此外,避免直接与True
或False
进行比较更为常见:
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
问题是默认参数[]