Validating and averaging student grades I have myself a little challenge tonight. I've tried to come up with the shortest code for the problem below (the code is pretty self explanatory, except determinGrade there which follows the rule


  A - 90-100%
    B - 80-89%
    C - 70-79%
    D - 60-69%
    F - Below 60%


The code has to be PEP8 complient and no imports (std included) are allowed. Tell me if you can shorten the code further.

isValidScore = lambda n: 0 &lt;= n &lt;= 100
calcAverage = lambda *args: sum(args)/len(args)
determinGrade = lambda s: ['F', 'D', 'C', 'B', 'A'][max(0, (min(s, 99)/10)-5)]


def getValidScore():
    while True:
        try:
            s = int(raw_input('Input score: '))
            if isValidScore(s):
                return s
        except ValueError:
            pass
        print('Score has to be an integer in the range 0 to 100')

if __name__ == "__main__":
    scores = [getValidScore() for _ in range(5)]
    print('The scores are: ' + str(scores))
    print('The average is: ' + str(calcAverage(*scores)))
    print('The grade is: ' + determinGrade(calcAverage(*scores)))
Although this passes the pep8 tool as of version 1.5.5,
this is not PEP8 compliant:


  
  Function names should be lowercase, with words separated by underscores as necessary to improve readability.
  Always use a def statement instead of an assignment statement that binds a lambda expression directly to an identifier.
  


If you convert the lambda expressions to def statements, the result will be longer, but better.

Also, these statements are a bit tightly packed for my taste:


calcAverage = lambda *args: sum(args)/len(args)
determinGrade = lambda s: ['F', 'D', 'C', 'B', 'A'][max(0, (min(s, 99)/10)-5)]



Would have been better this way, but PEP8 does not require it:

calcAverage = lambda *args: sum(args) / len(args)
determinGrade = lambda s: ['F', 'D', 'C', 'B', 'A'][max(0, (min(s, 99) / 10) - 5)]


In this last statement, there are some redundant parentheses, this is equivalent:

determinGrade = lambda s: ['F', 'D', 'C', 'B', 'A'][max(0, min(s, 99) / 10 - 5)]


Instead of the min hack for the value of 100, how about this way:

determinGrade = lambda s: ['F', 'D', 'C', 'B', 'A', 'A'][max(0, s / 10 - 5)]


Last but not least, beware that in Python 3, 27 / 10 will give you 2.7 instead of 2 as in Python 2. As such, the determinGrade will try to use a float as the list index, and your script will break. Adopting Python 3 is probably only a matter of time, so it's good to be prepare for that, and use // to ensure that you will get an integer index:

determinGrade = lambda s: ['F', 'D', 'C', 'B', 'A', 'A'][max(0, s // 10 - 5)]


Suggested implementation

Putting the above suggestions together:

def is_valid_score(n):
    return 0 &lt;= n &lt;= 100


def calc_average(*args):
    return sum(args) / len(args)


def determine_grade(s):
    return ['F', 'D', 'C', 'B', 'A', 'A'][max(0, s // 10 - 5)]


def get_valid_score():
    while True:
        try:
            s = int(raw_input('Input score: '))
            if is_valid_score(s):
                return s
        except ValueError:
            pass
        print('Score has to be an integer in the range 0 to 100')

if __name__ == "__main__":
    scores = [get_valid_score() for _ in range(5)]
    print('The scores are: ' + str(scores))
    print('The average is: ' + str(calc_average(*scores)))
    print('The grade is: ' + determine_grade(calc_average(*scores)))