Python学生成绩GUI程序报错:StudentView初始化缺少必填参数'student'
我正在开发一款学生信息与考试成绩管理GUI程序,支持计算成绩的均值、中位数、众数及标准差,还加了“Plot Scores”按钮展示成绩折线图。但运行时一直报这个错误:
TypeError: StudentView.init() missing 1 required positional argument: 'student'
下面是我用到的代码文件:
student.py
class Student: def __init__(self, student_id, name): self.student_id = student_id self.name = name self.test_scores = [] def add_test_score(self, score): self.test_scores.append(score) def average_test_score(self): if len(self.test_scores) == 0: return 0 return sum(self.test_scores)/len(self.test_scores) def get_test_scores(self): return self.test_scores
studentview.py
from breezypythongui import EasyFrame import matplotlib.pyplot as plt from student import Student class StudentView(EasyFrame): def __init__(self, model, student): EasyFrame.__init__(self) self.setSize(500, 200) self.model = model self.student = student student = Student(model.student_id, model.name, model.test_scores) student_view = StudentView(model, student) self.addLabel("Mean", row = 0, column = 0) self.addLabel("Median", row = 1, column = 0) self.addLabel("Mode", row = 2, column = 0) self.addLabel("Standard deviation", row = 3, column = 0) self.meanFld = self.addFloatField(value = 0.0, row = 0, column = 1, precision = 2) self.medianFld = self.addFloatField(value = 0.0, row = 1, column = 1, precision = 2) self.modeFld = self.addFloatField(value = 0.0, row = 2, column = 1, precision = 2) self.stdFld = self.addFloatField(value = 0.0, row = 3, column = 1, precision = 4) self.addLabel("Data", row = 0, column = 2, sticky = "NEW") self.scoreArea = self.addTextArea(text = "", row = 1, column = 2, width = 12, rowspan = 3) bp = self.addPanel(row = 4, column = 0, columnspan = 3, background = "black") bp.addButton(text = "Edit Score", row = 0, column = 0, command = self.editScore) bp.addButton(text = "Add score", row = 0, column = 1, command = self.addScore) bp.addButton(text = "Randomize scores", row = 0, column = 3, command = self.randomizeScores) bp.addButton(text="Plot Scores", row=0, column=4, command=self.plotScores) self.refreshData() def plotScores(self): scores = self.student.get_test_scores() positions = list(range(1, len(scores) + 1)) plt.plot(positions, scores, marker='o') plt.xlabel('Positions') plt.ylabel('Scores') plt.title('Student Test Scores') plt.show()
studentapp.py
""" File: studentapp.py The application for editing and analyzing student scores. """ from student import Student from studentview import StudentView def main(): """Creates the model and view and starts the app.""" model = Student("Ken", 10) StudentView(model) if __name__ == "__main__": main()
stats.py
""" File: stats.py Defines functions to compute the mean, median, std, and mode of a list of numbers. """ import math import random def mean(lyst): """Returns the mean of a list of numbers.""" return sum(lyst) / len(lyst) def frequencies(lyst): """Returns a dictionary keyed by the unique numbers and their frequencies in lyst.""" theDictionary = {} for number in lyst: freq = theDictionary.get(number, 0) theDictionary[number] = freq + 1 return theDictionary def mode(lyst): """Returns the mode of a list of numbers.""" theDictionary = frequencies(lyst) theMaximum = max(theDictionary.values()) for key in theDictionary: if theDictionary[key] == theMaximum: result = key break return result def modes(lyst): """Returns the modes of a list of numbers.""" theDictionary = frequencies(lyst) theMaximum = max(theDictionary.values()) result = [] for key in theDictionary: if theDictionary[key] == theMaximum: result.append(key) return result def median(lyst): """Precondition: lyst is non-empty. Returns the median of numbers in lyst.""" if len(lyst) == 0: raise RuntimeError("List must be non-empty. ") copy = list(lyst) copy.sort() midpoint = len(lyst) // 2 if len(lyst) % 2 == 1: return copy[midpoint] else: return mean([copy[midpoint - 1], copy[midpoint]]) def std(lyst): """Precondition: lyst is non-empty. Returns the standard deviation of the numbers in lyst.""" if len(lyst) == 0: raise RuntimeError("List must be non-empty. ") average = mean(lyst) differences = map(lambda x: x - average, lyst) squares = list(map(lambda x: x ** 2, differences)) return math.sqrt(mean(squares)) def getRandomList(size, lower, upper, unique = False): """Returns a list of randomly generate numbers within the given bounds.""" theList = [] for count in range(size): number = random.randint(lower, upper) if unique: while number in theList: number = random.randint(lower, upper) theList.append(number) return theList def main(): """Tests the functions.""" lyst = [3, 1, 7, 1, 4, 10] print("List:", lyst) print("Mode:", mode(lyst)) print("Median:", median(lyst)) print("Mean:", mean(lyst)) print("Standard deviation:", std(lyst)) print("Frequencies:", frequencies(lyst)) lyst.sort() print(lyst) lyst = [3, 1, 7, 1, 4] print("List:", lyst) print("Mode:", mode(lyst)) print("Median:", median(lyst)) print("Mean:", mean(lyst)) print("Standard deviation:", std(lyst)) print("Frequencies:", frequencies(lyst)) lyst.sort() print(lyst) lyst = getRandomList(10, 1, 10) print(lyst) lyst = getRandomList(10, 1, 10, unique = True) print(lyst) if __name__ == "__main__": main()
问题根源及修复方案
1. 直接触发报错的原因:调用StudentView时参数不足
StudentView的构造函数要求传入model和student两个参数,但studentapp.py的main函数里只传了model,少了一个参数。而且原代码里model本身就是Student实例,直接把它同时作为student参数传入即可,另外注意Student的参数顺序是student_id在前,name在后,原代码写反了。
修复后的studentapp.py:
""" File: studentapp.py The application for editing and analyzing student scores. """ from student import Student from studentview import StudentView def main(): """Creates the model and view and starts the app.""" # 纠正Student参数顺序:student_id在前,name在后 model = Student(10, "Ken") # 传入两个参数,model本身就是student实例 StudentView(model, model) if __name__ == "__main__": main()
2. StudentView初始化时的递归死循环错误
在studentview.py的__init__里,你又创建了Student和StudentView的实例,这会导致无限递归调用,程序直接卡死,必须删掉这两行错误代码。而且原代码创建Student时传了三个参数,但Student的构造函数只接受两个参数,test_scores是默认初始化的空列表,不需要传入。
3. 缺失refreshData方法的实现
原代码调用了self.refreshData()但没有实现这个方法,它是用来更新界面统计数据和成绩列表的核心方法,必须补充实现,同时要调用stats.py里的统计函数来填充界面字段。
4. 按钮回调方法缺失
Edit Score、Add score等按钮的回调函数没有实现,会导致点击按钮时报错,需要补充占位或完整逻辑。
修复后的studentview.py:
from breezypythongui import EasyFrame import matplotlib.pyplot as plt from student import Student import stats class StudentView(EasyFrame): def __init__(self, model, student): EasyFrame.__init__(self) self.setSize(600, 300) self.model = model self.student = student # 移除错误的递归实例化代码 # student = Student(model.student_id, model.name, model.test_scores) # student_view = StudentView(model, student) # 界面组件创建 self.addLabel("均值", row=0, column=0) self.addLabel("中位数", row=1, column=0) self.addLabel("众数", row=2, column=0) self.addLabel("标准差", row=3, column=0) self.meanFld = self.addFloatField(value=0.0, row=0, column=1, precision=2) self.medianFld = self.addFloatField(value=0.0, row=1, column=1, precision=2) self.modeFld = self.addFloatField(value=0.0, row=2, column=1, precision=2) self.stdFld = self.addFloatField(value=0.0, row=3, column=1, precision=4) self.addLabel("成绩数据", row=0, column=2, sticky="NEW") self.scoreArea = self.addTextArea(text="", row=1, column=2, width=15, rowspan=3) bp = self.addPanel(row=4, column=0, columnspan=3, background="black") bp.addButton(text="编辑成绩", row=0, column=0, command=self.editScore) bp.addButton(text="添加成绩", row=0, column=1, command=self.addScore) bp.addButton(text="随机生成成绩", row=0, column=2, command=self.randomizeScores) bp.addButton(text="绘制成绩折线图", row=0, column=3, command=self.plotScores) self.refreshData() def refreshData(self): """刷新界面上的统计数据和成绩列表""" scores = self.student.get_test_scores() # 更新成绩文本区域 self.scoreArea.setText("\n".join(map(str, scores))) # 处理空成绩列表的情况 if not scores: self.meanFld.setNumber(0.0) self.medianFld.setNumber(0.0) self.modeFld.setNumber(0.0) self.stdFld.setNumber(0.0) return # 调用stats模块的函数计算统计值 mean_val = stats.mean(scores) median_val = stats.median(scores) mode_val = stats.mode(scores) std_val = stats.std(scores) # 更新界面字段 self.meanFld.setNumber(mean_val) self.medianFld.setNumber(median_val) self.modeFld.setNumber(mode_val) self.stdFld.setNumber(std_val) def plotScores(self): scores = self.student.get_test_scores() if not scores: self.messageBox("提示", "没有成绩数据可绘制!") return positions = list(range(1, len(scores) + 1)) plt.plot(positions, scores, marker='o') plt.xlabel('考试次数') plt.ylabel('成绩') plt.title(f'{self.student.name}的考试成绩') plt.show() # 实现按钮回调方法(可根据需求完善) def editScore(self): self.messageBox("提示", "编辑成绩功能待实现") def addScore(self): # 弹出输入框添加成绩 score = self.promptFloat("输入成绩", "请输入0-100之间的成绩", min=0, max=100) if score is not None: self.student.add_test_score(score) self.refreshData() def randomizeScores(self): # 生成5个0-100的随机成绩 scores = stats.getRandomList(5, 0, 100) self.student.test_scores = scores self.refreshData()
内容的提问来源于stack exchange,提问作者Shane Beacham

