Hoping to get feedback on how this program could be written in the most pythonic way. Also welcome any criticisms of styling as I know this is not in accordance with pep-8from collections import namedtuplea = namedtuple('assignment', 'weight scores')def average(scores:list):    '''average a list of scores'''    return sum(scores)/len(scores)def get_grade(grades:list):    '''compute final grade based on scores and their weights'''    result = 0    for a in grades:        result += average(a.scores) * a.weight    return result def main():   grades = [a(.30, [18/45, 11/55]),             a(.20, [3/10, 7.5/10, 10/10]),             a(.10, [9/10, 9/10, 10/10, 10/10, 8/10,                6/10, 10/10, 10/10]),             a(.40, [29/65]),              a(.01, [1/1])]   print(get_grade(grades))main()
Compute a students grade based on weight of assignments
python;beginner
from collections import namedtupleYou should put blank lines after imports, and between function/class definitions. a = namedtuple('assignment', 'weight scores')Using a namedtuple for a simple data class like this is a good idea, but it should still be named as a class; Assignment.def average(scores:list):    '''average a list of scores'''    return sum(scores)/2This function has an obvious bug; what about lists of scores with lengths other than two? Also you type the parameter but not the return value, and should again have some more whitespace; I'd write:def average(scores: list) -> float:    Average a list of scores.    return sum(scores) / len(scores)See PEP-257 for docstring conventions. def get_grade(grades:list):    '''compute final grade based on scores and their weights'''    result = 0    for a in grades:        result += average(a.scores) * a.weight    return result I think you could simplify this with a bit more OOP. If we subclass the named tuple we can add a read only calculated attribute to it:class Assignment(namedtuple('Assignment', 'weight scores')):    @property    def result(self) -> float:        return average(self.scores) * self.weightThen your function becomes:def get_grade(assignments: list) -> float:    Compute final grade based on scores and their weights.    return sum(a.result for a in assignments)Note the revised parameter name, which better describes the input. def main():   grades = [a(.30, [18/45, 11/55]),             a(.20, [3/10, 7.5/10, 10/10]),             a(.10, [9/10, 9/10, 10/10, 10/10, 8/10,                6/10, 10/10, 10/10]),             a(.40, [29/65]),              a(.01, [1/1])]   print(get_grade(grades))main()To keep things looking consistent without introducing a lot of indentation, I usually split lists with long elements across multiple lines as follows:assignments = [    Assignment(.30, [18/45, 11/55]),    ...    Assignment(        .10,        [9/10, 9/10, 10/10, 10/10, 8/10, 6/10, 10/10, 10/10]    ),    ...]Note splitting between, rather than within, the two parameters. Also you should guard the invocation of the entry point as follows:if __name__ == '__main__':     main()This means you can import this functionality more easily for testing and reuse. 