【问题标题】:Getting an average in a function in Python在 Python 中获取函数的平均值
【发布时间】:2014-07-05 03:25:34
【问题描述】:

我正在尝试学习 Python,但我被卡住了。一切都很顺利,直到最后一个函数是:

def get_class_average(students): 

到目前为止,一切正常,但是在最后一个函数中,我不知道如何使它工作。我正在尝试获取每个学生的平均值,然后计算这些平均值的平均值,换句话说就是“班级平均值”所以,我只想知道最后一个函数的答案,而不更改最后一个函数之前的任何函数一:

lloyd = {
    "name": "Lloyd",
    "homework": [90.0, 97.0, 75.0, 92.0],
    "quizzes": [88.0, 40.0, 94.0],
    "tests": [75.0, 90.0]
}
alice = {
    "name": "Alice",
    "homework": [100.0, 92.0, 98.0, 100.0],
    "quizzes": [82.0, 83.0, 91.0],
    "tests": [89.0, 97.0]
}
tyler = {
    "name": "Tyler",
    "homework": [0.0, 87.0, 75.0, 22.0],
    "quizzes": [0.0, 75.0, 78.0],
    "tests": [100.0, 100.0]
}



def average(numbers):
       total = sum(numbers)
       return float(total) / len(numbers)


def get_average(student):
       homework = average(student["homework"]) 
       quizzes = average(student["quizzes"]) 
       tests = average(student["tests"]) 
       return 0.1 * average(student["homework"]) + 0.3 * average(student["quizzes"])    +     0.6 * average(student["tests"])

def get_letter_grade(score):
       if score >= 90:
              return "A"
       elif score >= 80:
              return "B"         
       elif score >= 70:
              return "C"
       elif score >= 60:
              return "D"
       else:
              return "F"

def get_class_average(students):
       results = []
       for student in results:
              get_average(student)
              results.append(student)
              average(student)
              return results

students = [lloyd,alice,tyler]

print get_class_average(students)

我终于找到了解决方案。所以,我只想在下面发布最后一个函数 get_class_average(students) 的更正代码。现在可以了:

def get_class_average(students):
       results = []
       for each in students:
              studentavg = float(get_average(each))
              results.append(studentavg)
       return average(results)

students = [lloyd,alice,tyler]

print get_class_average(students)

【问题讨论】:

  • 你应该先浏览一下前面的函数并尝试了解它们是如何工作的。
  • 在 get_class_average 中,当您应该迭代学生时,您正在迭代结果(空列表)。 for student in students: 也将 return 放在 for 循环之外 - 否则它只会返回第一个学生。这应该会为您解决问题。
  • Ignacio Vazquez-Abrams 我了解它们是如何工作的,我将前面的函数一一、一步一步地编写。在最后一个函数中,我显然遗漏了一些东西
  • @Jordan 我试过了,你应该修复它可能是对的,但即使我改变它,它也不起作用
  • 好的,不要将 student 附加到结果中,而是附加 get_average(student)。这可能是您正在寻找的。 results.append(get_average(student)) 然后返回该集合的平均值。 return average(results)

标签: python list average


【解决方案1】:

你不应该取平均值,你知道的。我已经更正了您的代码以使其正常工作。这里是:

lloyd = {
    "name": "Lloyd",
    "homework": [90.0, 97.0, 75.0, 92.0],
    "quizzes": [88.0, 40.0, 94.0],
    "tests": [75.0, 90.0]
}
alice = {
    "name": "Alice",
    "homework": [100.0, 92.0, 98.0, 100.0],
    "quizzes": [82.0, 83.0, 91.0],
    "tests": [89.0, 97.0]
}
tyler = {
    "name": "Tyler",
    "homework": [0.0, 87.0, 75.0, 22.0],
    "quizzes": [0.0, 75.0, 78.0],
    "tests": [100.0, 100.0]
}



def average(numbers):
    total = sum(numbers)
    return float(total) / len(numbers)


def get_average(student):
       homework = average(student["homework"]) 
       quizzes = average(student["quizzes"]) 
       tests = average(student["tests"]) 
       return 0.1 * average(student["homework"]) \
            + 0.3 * average(student["quizzes"]) \
        + 0.6 * average(student["tests"])

def get_letter_grade(score):
       if score >= 90:
              return "A"
       elif score >= 80:
              return "B"         
       elif score >= 70:
              return "C"
       elif score >= 60:
              return "D"
       else:
              return "F"

def get_class_average(students):
    results = []
    for student in students:
        a = get_average(student)
        results.append(a)
    return average(results)

students = [lloyd,alice,tyler]

print get_class_average(students)    

由于您是 python 新手,我花了一两个小时的大部分时间重写了您的代码以使用 python 的各种功能,包括文档字符串、生成器、列表推导、类以及映射-减少模式,以及一些新的导入以及如何对模块进行单元测试。我知道您说过要对代码进行最少的更改,但我觉得简单地解决您的问题并继续前进对您来说是不礼貌的。我想给你一些 sn-ps,使用你的例子,我自己学习 python 时建立和学习的。

我的示例比您的示例更长更大,我绝不建议您采取任何超越最短和最简单路线的路径,我只是提供一个示例。当您阅读本文时不要惊慌,只需仔细阅读并使用它并尽您所能利用它。在它开始有意义之前,您可能必须让它在您的头脑和文件系统中反复思考一段时间。

如果你想知道if __name__ == "__main__": 的所有垃圾是关于什么的,我建议你将我的代码保存在一个名为Student.py 的文件中,然后从python 解释器会话中调用import Student。注意会发生什么不同:)。此外,在同一个会话中,在调用import Student(当然,来自同一个目录Student.py 保存在其中)之后,键入help(Student)——我保证这将是值得您花时间的。

from __future__ import division # to get rid of having to use float()
from math       import floor, log10 # for a helper function

class Student:
    """
    A class encapsulating elements of a student object. 
    Notable properties:
    homework_weight(0.1) --> a float multiplying student's homework average
    quiz_weight(0.3)     --> a float multiplying the student's quiz average
    test_weight(0.6)     --> a float multiplying the student's test average
    delimiter            --> a character used to separate fields in __str__
    """
    sig_figs        = 2
    homework_weight = 0.1
    quiz_weight     = 0.3
    test_weight     = 0.6
    delimiter       = '|'

    def __init__(self, name, homework, quizzes, tests):
        """
        Constructor for the Student object. Parameters are as follows:
        name      --> a string containing the student's name
        homework  --> a list of floats containing homework grades
        quizzes   --> a list of floats containing quiz grades
        tests     --> a list of floats containing test grades
        """
        self.__name     = name
        self.__homework = homework
        self.__quizzes  = quizzes
        self.__tests    = tests

    def get_name(self):
        """ Returns the current object's name """
        return self.__name

    def get_homeworks(self):
        """ yields a generator object for student's homework grades"""
        for i in self.__homework: yield i

    def get_quizzes(self):
        """ yields a generator object for student's quiz grades"""
        for i in self.__quizzes:  yield i

    def get_tests(self):
        """ yields a generator object for student's test grades"""
        for i in self.__tests:    yield i


    @classmethod
    def from_dict(cls, student_dict):
        """
        Creates a Student object from a dictionary. The dictionary must
        contain the following key-value pairs:
        'name'     : student_name
        'homework' : list of floats for homework grades
        'quizzes'  : list of floats for quiz grades
        'tests'    : list of floats for test grades
        """
        d = student_dict
        return cls(d['name'], d['homework'], d['quizzes'], d['tests'])

    def __str__(self):
        """
        Returns a string representation of the current
        object. The representation will be in the form
        of the fields separated by the default separator
        character (currently '|').
        """
        conv = lambda x, d: d.join(map(str, x))
        sep  = self.delimiter

        buff = ''
        buff +=      self.__name           + sep
        buff += conv(self.__homework, sep) + sep
        buff += conv(self.__quizzes,  sep) + sep
        buff += conv(self.__tests,    sep) 

        return buff

    def __repr__(self):
        """
        Returns a representation of the current object. In this
        case, we will return the same thing as __str__
        """
        return str(self)


    def to_dict(self):
        """
        Returns a dict representation of this object containing
        the keys ['name', 'homework', 'quizzes', 'tests'] where
        homework, quizzes, and tests are lists of floats.
        """
        obj = {}
        obj['name']     = self.__name
        obj['homework'] = self.__homework
        obj['quizzes']  = self.__quizzes
        obj['tests']    = self.__tests
        return obj



    def get_student_average(self, tuplify=False):
        """
        This method retrieves the student's class average according
        to predefined weighting rules. In this method, we average the
        list of scores together for the student's homework, quizzes,
        and tests, multiply them by their respective weights, and
        sum them together to obtain the final score. See implementation
        for more details.
        """
        hw = self.__homework
        qu = self.__quizzes
        ts = self.__tests

        if(0 not in map(len, [hw, qu, ts])): #division by zero, bla bla
            avg  = lambda l: sum(l)/len(l)
            avgs = map(avg,  [hw, qu, ts])
            hwa  = avgs[0] * Student.homework_weight
            qua  = avgs[1] * Student.quiz_weight
            tsa  = avgs[2] * Student.test_weight
            if tuplify is False:
                return sum([hwa, qua, tsa])
            else: 
                return (hwa, qua, tsa)

    def get_student_averages(self):
        """
        This method retrieves the student's class averages according
        to predefined weighting rules. In this method, we average the
        list of scores together for the student's homework, quizzes,
        and tests, multiply them by their respective weights, and return
        a set of them as a tuple where (homeworka, quiza, testa)
        See implementation for more details. 
        """
        return self.get_student_averages(tuplify=True)

    def get_student_letter_grade(self):
        """
        This method takes a student's letter score according to their
        average (computed by self.get_student_average()) and fetches
        the appropriate letter grade (A through F)
        """
        score = self.get_student_average()
        if   score >= 90:   return 'A'
        elif score >= 80:   return 'B'
        elif score >= 70:   return 'C'
        elif score >= 60:   return 'D'
        else:           return 'F'

    @staticmethod
    def __get_significant_average(grade_list):
        """ 
        Takes a list of grades and returns an average, does the average
        using proper significant figures according to a global variable
        grade_list -- a list of floats to average
        """
        sigfig = lambda x, n: round(x, -int(floor(log10(x))) + (n - 1))
        avg    = sigfig(sum(grade_list)/len(grade_list), num_figs)
        print '\t\t' + str(avg)
        return avg

    @staticmethod
    def get_class_set(student_list):
        """
        Generates a student object from a list of students
        and by assembling all the student's grades for each
        assignment and then using methods in the Student class
        to compute what we need to compute. 
        """
        # this is REALLY slick. What we're going to do is create a 
        # generator  generators of the student's homework and test
        # grades, but for the quizzes we will make regular list of
        # lists. 
        hwg = (x.get_homeworks()            for x in student_list)
        qwg = [[q for q in y.get_quizzes()] for y in student_list]
        twg = (z.get_tests()                for z in student_list)

        tl = lambda l: [x for x in l]
        # ^This is a lambda expression that converts a generator l
        # to a list (hence tl)



        # since each get_blabla() function returns a generator
        # and since each *wg variable is a generator of a generator
        # we will eventually get sublists of sublists of sublists
        # on and on and on and need to flatten them. Here are three
        # ways to do that. 
    # http://stackoverflow.com/questions/952914/making-a-flat-list-out-of-list-of-lists-in-python 
        hwl = [item for sublist in hwg for item in sublist]
        qwl = sum(qwg, []) 
        twl = reduce(lambda x,y: tl(x)+tl(y), twg)

        class_set = Student('class_whole_set', hwl, qwl, twl)
        return class_set




if __name__ == "__main__":

    lloyd = {
        "name": "Lloyd",
        "homework": [90.0, 97.0, 75.0, 92.0],
        "quizzes": [88.0, 40.0, 94.0],
        "tests": [75.0, 90.0]
    }

    alice = {
        "name": "Alice",
        "homework": [100.0, 92.0, 98.0, 100.0],
        "quizzes": [82.0, 83.0, 91.0],
        "tests": [89.0, 97.0]
    }

    tyler = {
        "name": "Tyler",
        "homework": [0.0, 87.0, 75.0, 22.0],
        "quizzes": [0.0, 75.0, 78.0],
        "tests": [100.0, 100.0]
    }

    slloyd  = Student.from_dict(lloyd)
    salice  = Student(alice['name'], alice['homework'], alice['quizzes'], alice['tests'])
    styler  = Student.from_dict(tyler)

#  YOU COULD DO THIS!
#   print 'lloyd dict'
#   print '\t' + str(sdlloyd)
#
#   print 'alice ctor'
#   print '\t' + str(slloyd)
#
#   print 'slloyd name: ' + slloyd.to_dict()['name']
#   print 'slloyd home: ' + str(map(str, slloyd.to_dict()['homework']))
#   print 'slloyd quiz: ' + str(map(str, slloyd.to_dict()['quizzes']))
#   print 'slloyd test: ' + str(map(str, slloyd.to_dict()['tests']))
#   print 'slloyd avg:  ' + str(slloyd.get_student_average())
#
#   conv = lambda x: str(map(str, x))
#   print 'salice name: ' + salice.get_name()
#   print 'salice home: ' + conv(salice.get_homeworks())
#   print 'salice quiz: ' + conv(salice.get_quizzes())
#   print 'salice test: ' + conv(salice.get_tests())
#   print 'salice avg:  ' + str(salice.get_student_average())
#


    """Unit test some object obj"""
    def unit_test(objname, obj):
        conv = lambda x: str(map(str, x))
        print str(objname) + ' name: ' + obj.get_name()
        print str(objname) + ' home: ' + conv(obj.get_homeworks())
        print str(objname) + ' quiz: ' + conv(obj.get_quizzes())
        print str(objname) + ' test: ' + conv(obj.get_tests())
        print str(objname) + ' avg : ' + str(obj.get_student_average())
        print str(objname) + ' let : ' + obj.get_student_letter_grade()

    sclss  = Student.get_class_set( [slloyd, salice, styler] )
    unit_test('sclss', sclss)
    unit_test('slloyd', slloyd)
    unit_test('salice', salice)
    unit_test('styler', styler)

如果这对您有帮助,以及您是否对此代码的任何方面感到困惑,请告诉我。欢迎来到堆栈溢出:)

【讨论】:

  • 非常感谢您的回答。我仍在研究您的第二个答案的更长示例代码,这确实非常复杂。我非常感谢它。但是,第一个简单的版本仍然没有返回我正在寻找的东西。我想用最后一个函数 get_class_average 得到的是首先使用函数 get_average() 获取每个学生的平均值,以某种方式将其附加到结果中,最后返回班级平均值,这是每个学生的平均值,通过使用函数average()。请让我知道你的想法。
  • 不客气。如果我的回答对您有很大帮助,请不要忘记将其标记为答案。我的第二段代码一旦你全部追踪出来就不是那么复杂了——我的建议是打印出来并用笔和纸手工追踪。此外, get_class_average 的简单版本完全按照您所说的进行;即使从技术上讲,平均一个平均值是不正确的做法。你得到了哪些你不喜欢的结果?
  • @alvonellos 我编辑了我的原始问题并发布了问题的解决方案。请看我上面的编辑。
  • 很高兴我的回答有帮助。
【解决方案2】:

lloyd = { "name": "Lloyd", "homework": [90.0, 97.0, 75.0, 92.0], "quizzes": [88.0, 40.0, 94.0], "tests": [75.0, 90.0] } alice = { "name": "Alice", "homework": [100.0, 92.0, 98.0, 100.0], "quizzes": [82.0, 83.0, 91.0], "tests": [89.0, 97.0] } tyler = { "name": "Tyler", "homework": [0.0, 87.0, 75.0, 22.0], "quizzes": [0.0, 75.0, 78.0], "tests": [100.0, 100.0] }

在下面添加你的函数!

def 平均值(数字): 总计 = 浮点数(总和(数字)) 返回总/长度(数字)

def get_average(学生): 作业=平均(学生['作业'])* 0.1 测验=平均(学生['测验'])* 0.3 测试=平均(学生['测试'])* 0.6 返回(作业+测验+测试)

def get_letter_grade(分数): 如果分数 > 90 或分数 == 90: 返回“A” elif 得分 > 80 或得分 == 80 且得分 70 或得分 == 70 且得分 60 或得分 == 60 且得分

学生 = [劳埃德,爱丽丝,泰勒]

def get_class_average(学生): 结果 = [] 对于学生中的学生: print "student: %s, srednia %s" % (student['name'],get_average(student)) results.append(get_average(学生)) 打印结果 打印get_average(学生) 返回平均值(结果)

打印get_class_average(学生)

【讨论】:

    【解决方案3】:

    这对我有用:

    lloyd = {
      "name": "Lloyd",
      "homework": [90.0, 97.0, 75.0, 92.0],
      "quizzes":  [88.0, 40.0, 94.0],
      "tests":    [75.0, 90.0]
    }
    alice = {
      "name": "Alice",
      "homework": [100.0, 92.0, 98.0, 100.0],
      "quizzes":  [82.0, 83.0, 91.0],
      "tests":    [89.0, 97.0]
    }
    tyler = {
      "name": "Tyler",
      "homework": [0.0, 87.0, 75.0, 22.0],
      "quizzes":  [0.0, 75.0, 78.0],
      "tests":    [100.0, 100.0]
    }
    
    # Add your function below!
    def average(numbers):
      total = 0.0
      total = sum(numbers)
      total = float(total) / len(numbers)
      return total
    
    def get_average(student):
      hweight = 0.1
      qweight = 0.3
      tweight = 0.6
      homework = average(student["homework"])
      quizzes  = average(student["quizzes"])
      tests    = average(student["tests"])
      total = (homework * hweight) + (quizzes * qweight) + (tests * tweight)
      return total
    
    def get_letter_grade(score):
      if score >= 90:
        return 'A'
      elif score < 90 and score >= 80:
        return 'B'
      elif score < 80 and score >= 70:
        return 'C'
      elif score < 70 and score >= 60:
        return 'D'
      else:
        return 'F'
    
    def get_class_average(class_list):
      results = []
      for student in class_list:
        running = get_average(student)
        results.append(running)
      return average(results)
    
    students = [lloyd, alice, tyler]
    print "The Average for the class is:\n"
    print get_class_average(students)
    print
    print "Which corresponds to a letter grade of:\n"
    print get_letter_grade(get_class_average(students))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多