使用类和对象计算学生GPA

时间:2016-06-07 05:19:04

标签: python python-3.x

这是我的代码:

class student:
    def __init__(self):
        self.totalSumOGrades = 0
        self.numberOGrades = 0

    def getAverageScore(self):
        return (self.totalSumOGrades / self.numberOGrades)

    def addGrade(self,grade):
        self.totalSumOGrades = str(grade)
        self.numberOGrades = self.numberOGrades + 1
        return (self.totalSumOGrades)


class GPA:
    def __init__(self,grade):
        self.grade = grade
        self.score = 0


    def gradesScore(self):
        gradeLetter = self.grade[0]
        gradeSign = ' '
        if (len(self.grade)) == 2:
            gradeSign = self.grade[1]

        if (gradeLetter == 'A'):
            self.score = 4
        elif (gradeLetter == 'B'):
            self.score = 3
        elif (gradeLetter == 'C'):
            self.score = 2
        elif (gradeLetter == 'D'):
            self.score = 1
        elif (gradeLetter == 'F'):
            self.score = 0

        if (gradeSign == '+'):
            self.score += 0.3
        elif (gradeSign == '-'):
            self.score -= 0.3


    def getScore(self):
        self.gradesScore()
        return self.score

我在一张纸上需要这两个课程。我遇到的问题是正在为GPA课程采取的论点是“getScore”正在计算的内容。我需要它,所以来自班级学生的addGrade会增加一个成绩,我可以让“getScore”计算这些成绩。我该如何解决这个问题?

1 个答案:

答案 0 :(得分:1)

因此,我承诺提供答案/反馈版本,以帮助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类的成员实例。这会使学生班级接近一个多余的层(按原样),但实际上你现在会填写个人信息,以识别学生被建模到学生实例中。

当我在我的机器上运行上面的代码时(使用python 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。这将与更真实的生活相匹配,其中存储可能允许识别某人或可能有可能披露某人的私人细节的数据通常被分成散布盐渍哈希以附加到需要反向引用的所有类实例,但是只能在一个特别安全的地方保留映射回到真实姓名,日期和地点等。

也可以从任何学生实例中引入(除了增加的中位数)最小/最大,即最差/最佳分数或等级“信息”,甚至可以尝试对分数进行简单的线性回归以找到一些“趋势”。

另一类扩展试图“覆盖”测试中的所有路径。

另一种“搞砸”的方法可能是,更加优雅的迷你语言内部映射,其中“收集阶段”(从等级映射到数值的那些)完全转换为整数,例如。通过缩放全部十倍,所以有无损算术,价格考虑“报告”预期的反向变换的实际分数(即样本4.3而不是43),但也有利于重新定位来自任何得分和记忆只能执行一个最后的“四舍五入”步骤。

另请注意有用的pep8工具或例如python3 -m pep8 so_get_gpa_for_student_edited.py既没有错误也没有警告。

另一个提示,通常是在开发过程中以及扩展对象/添加胎儿时,名称会慢慢偏离界限。到目前为止(对我来说)GradePointAverage是匹配的类/类型名称,因为我经常接受与算术平均值相比的中位数作为有用的双胞胎信息。但如果我已经说过了。趋势方法,那么它将是进一步分离功能或重命名类的好时机。

同时决定一致性错误策略也有很大帮助。在上面的代码中,我们主要陈述问题类,但是例如。不报告确切导致问题的原因。在许多情况下,这是可以的,甚至是想要的,但在其他情况下,可能会在响应中添加一些细节。

最后一个细节:只是让你知道如何首先定义所有接口方法,然后逐步实现这些逐步测试我还添加了一个技巧,以便在计划somethig时发出信号,但尚未实现。在这里,我只需在best_score方法中返回NotImplemented。也可能会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选项和(预)生产当调用尚未实现的方法或函数更可能是使用错误时,我切换到例外,您的里程可能会有所不同......

请随意发表评论(如果我误读了这项任务),或者我忘记评论与您的​​代码比较时发现的更改。