因此,我承诺答复/反馈版本,以帮助OP走过并挑选一些新问题 - 在这里(希望火车黑客有足够的高质量来展示一些概念并提供良好的开始创建基于此的真正解决方案):
#! /usr/bin/env python
from __future__ import division, print_function
class GradePointAverage(object):
"""Implements a "Grade Point Average" (GPA) calculation.
Note: It keeps all grades to offer an incremental update path.
"""
FILL_CHAR_ZERO_ADJUST = '.'
VALID_LETTERS = ('A', 'B', 'C', 'D', 'E', 'F')
VALID_ADJUSTMENTS = ('+', FILL_CHAR_ZERO_ADJUST, '-')
BASE_SCORE_MAP = dict(zip(reversed(VALID_LETTERS), (0., 1., 2., 3., 4.)))
ADJ_SCORE_MAP = dict(zip(VALID_ADJUSTMENTS, (0.3, 0., -0.3)))
def __init__(self, grades=None):
"""Inintializes the _grades, a sequence of canonical grade
values e.g. ['A+', 'B-'] where any grade recieved is
mapped to uppercase letter plus either ''|'+'|'-' or
and exception ValueError is thrown.
"""
if grades is None:
self._grades = list()
else:
self._grades = [self.canonicalize_grade(g) for g in grades]
def __repr__(self):
"""Helper to (de)serialize and put more in print et al."""
return ('GradePointAverage(%s)' % (str(self._grades)))
def add_grades(self, grades):
"""Add a new result/grade to data."""
for g in grades:
self.add_grade(g)
def add_grade(self, grade):
"""Add a new result/grade to data."""
self._grades.append(self.canonicalize_grade(grade))
def count_grades(self):
"""Return the count of grades, the scoring is based upon."""
return len(self._grades)
def grades(self):
"""Return the grades as list, the scoring is based upon."""
return self._grades
def canonicalize_grade(self, grade):
"""Ensure grade is valid, ensure uppercase letter plus either
''|'+'|'-' on output. If invalid, let raise or throw ValueError. """
c_grade = grade.strip().upper() # May raise
if 1 <= len(c_grade) <= 2:
if len(c_grade) < 2:
c_grade += self.FILL_CHAR_ZERO_ADJUST
else:
raise ValueError("Invalid grade length")
if c_grade[0] not in self.VALID_LETTERS:
raise ValueError("Invalid main grade")
if c_grade[1] not in self.VALID_ADJUSTMENTS:
raise ValueError("Invalid grade adjustment")
return c_grade
def _score(self, canonical_grade):
"""Calculate score from canonical grade."""
base, adj = canonical_grade[0], canonical_grade[1]
return self.BASE_SCORE_MAP[base] + self.ADJ_SCORE_MAP[adj]
def average_score(self):
"""Calculate average score."""
if not self.count_grades():
return None
# implicit else:
score_sum = sum(self._score(c_g) for c_g in self._grades)
return score_sum/float(self.count_grades())
def median_score(self):
"""Calculate median score."""
if not self.count_grades():
return None
# implicit else:
middle_index = self.count_grades() // 2
return sorted([self._score(c_g) for c_g in self._grades])[middle_index]
def best_score(self):
"""retrieve highest score."""
return NotImplemented
class Student:
"""Models student with updateable Grade Point Average."""
def __init__(self, grades):
self._gPA = GradePointAverage(grades)
self.number_of_grades = self._gPA.count_grades()
def __repr__(self):
"""Helper to (de)serialize and put more in print et al."""
return ('Student(%s)' % (str(self._gPA.grades())))
# Delegated/proxy methods
def average_score(self):
return self._gPA.average_score()
def count_grades(self):
return self._gPA.count_grades()
def grades(self):
return self._gPA.grades()
def median_score(self):
return self._gPA.median_score()
def best_score(self):
return self._gPA.best_score()
def add_grade(self, grade):
return self._gPA.add_grade(grade)
def add_grades(self, grades):
return self._gPA.add_grades(grades)
def main():
"""Drive some tests on "scored" Students."""
print('Positive test cases:')
print('... service class under test:')
gPA = GradePointAverage(['a+', 'c-'])
print(gPA)
print('... main class under test:')
student = Student(['F+'])
print(student)
print(student.count_grades())
print(student.average_score())
print(student.median_score())
a_grade = 'E-'
print("Added %s" % (a_grade,))
student.add_grade('E-')
print(student.count_grades())
print(student.average_score())
print(student.median_score())
some_grades = ['E', 'b+', 'b-', 'c+', 'D', 'D']
print("Added %s" % (str(some_grades),))
student.add_grades(some_grades)
print(student.count_grades())
print(student.average_score())
print(student.median_score())
print(student.grades())
print('Negative test cases:')
print(student.best_score())
print('... too long:')
try:
_ = GradePointAverage(['aa+', 'no_impact'])
except ValueError as e:
print(e)
print('... wrong grade letter:')
try:
_ = GradePointAverage(['z', 'no_impact'])
except ValueError as e:
print(e)
print('... wrong adjustment:')
try:
_ = GradePointAverage(['A*', 'no_impact'])
except ValueError as e:
print(e)
print('... wrong grade "type" we did let it just bubble:')
try:
_ = GradePointAverage([42, 'no_impact'])
except AttributeError as e:
print(e)
if __name__ == '__main__':
main()
所以学生实例始终代表等级和分数相关任务的GradePointsAverage类的成员实例。这会将学生课程移近一个多余的层次(按原样),但实际上您现在可以将识别正在建模的学生的个人信息填入Student实例。
当我在我的机器上面的代码运行(与蟒蛇V2解释):
Positive test cases:
... service class under test:
GradePointAverage(['A+', 'C-'])
... main class under test:
Student(['F+'])
1
0.3
0.3
Added E-
2
0.5
0.7
Added ['E', 'b+', 'b-', 'c+', 'D', 'D']
8
2.1625
2.0
['F+', 'E-', 'E.', 'B+', 'B-', 'C+', 'D.', 'D.']
Negative test cases:
NotImplemented
... too long:
Invalid grade length
... wrong grade letter:
Invalid main grade
... wrong adjustment:
Invalid grade adjustment
... wrong grade "type" we did let it just bubble:
'int' object has no attribute 'strip'
[Finished in 0.0s]
一个IMO应不超过工程师玩具的问题,但是这一次可能会提供有趣的支线任务,如存储哈希/带有学生实例的匿名ID。这将匹配更多的现实生活,其中可能允许识别个人或可能具有披露个人隐私细节的数据的存储通常被分成散布的腌制散列以附着到需要反参照的所有类别实例,但只需在一个特别安全的地方将映射保留回实名,日期和地点等。
也可以引入(除了增加的中位数)还有来自任何学生实例的最小/最大即最差/最佳得分或等级“信息”,甚至可以对得分进行简单线性回归以找到一些“趋势”。
另一类扩展将尝试“覆盖”测试中的所有路径。
的另一种方法,以“打击的事情了”可能是,一个更elgant迷你语言内部映射,其中“收集阶段”(从等级到数值的映射)完全转化为整数如。通过缩放所有十倍因而具有无损算术,并且价格考虑“报告”预期的回归变换的实际分数(即,样本4.3而不是43),而且还具有容易地重新分级任何分数和记忆只执行一个最后的“舍入”步骤。
还要注意有用的pep8工具或例如python3 -m pep8 so_get_gpa_for_student_edited.py
不会给出错误或警告。
另一个暗示,经常在开发过程中,当扩展对象/添加fetaures时,名称慢慢地偏离界限。直到现在(对我来说)GradePointAverage
是一个匹配的类/类型名称,因为我经常接受一个中位数与算术平均数作为有用的双胞胎信息。但如果我已经进入了说。一种趋势方法,那么它将是进一步分离功能或重命名类的好时机。
而且决定一个consisten错误的策略有很大帮助。在上面的代码中,我们主要说明问题类,但是例如。不要报告究竟是什么导致了问题。在很多情况下,这是可以的,甚至是想要的,但在其他情况下,可能会在响应中添加一些细节。
最后一个细节:就是让你知道如何首先定义所有的接口方法,然后在增量测试中逐一实现这些方法。我还添加了其中一个技巧来指示somethig计划时,但尚未实现。在这里,我只需返回NotImplemented
best_score方法。我们也可以raise NotImplementedError("Method_best_score")
代替,但因为这会导致:
File "/Users/sthagen/tmp/so_get_gpa_for_student_edited.py", line 184, in <module>
main()
File "/Users/sthagen/tmp/so_get_gpa_for_student_edited.py", line 157, in main
print(student.best_score())
File "/Users/sthagen/tmp/so_get_gpa_for_student_edited.py", line 117, in best_score
return self._gPA.best_score()
File "/Users/sthagen/tmp/so_get_gpa_for_student_edited.py", line 90, in best_score
raise NotImplementedError("Method best_score")
NotImplementedError: Method best_score
我经常活跃在创建过程中,从“零”的更安静return NotImplemented
选项,并在(预)生产时,一个尚未实现的方法的调用或功能更可能是在使用中的错误,我切换到例外,你的里程可能会有所不同...
请随时发表评论(如果我误读任务),或者如果我忘记评论你所发生的变化当比较你的代码smaple。
您是否使用纸质电脑:-)?我没有完成“在一张纸上需要两节课”的任务。在底部的其他散文,是这样的要求,如果一个学生已经有两个等级,并从这些积分得分,如果一个额外的三年级/结果被添加到他的“无论”,总分是积分现在重新计算了所有三个结果的输入?建议也可以为少数可能的有效成绩使用表格解析器,而不是使用if-elsing“眼睛”(也许可以尝试和比较)PEP8可以帮助您了解很多关于Python语言的知识。 – Dilettant
...建议遵循PEP8将学生班重新命名为学生,最后但并非最不重要的是:什么是GPA(我不是美国美国人)作为班级,它可能会更好骆驼案件(这意味着什么) 。不要忘记:说明最重要的是:我们开始帮助我思考,因为你真的尝试并展示它。谢谢。 – Dilettant
平均分... – Guy