4
\$\begingroup\$

I'm a C# developer looking to learn more about Python and how to think in a more functional programming manner.

I have the following which takes a series of grades and returns the average:

grades = [100, 100, 90, 40, 80, 100, 85, 70, 90, 65, 90, 85, 50.5]

def grades_sum(scores):
    total = 0
    for score in scores:
        total += score
    return total

def grades_average(grades):
    return grades_sum(grades) / float(len(grades))

print(grades_average(grades))

What are some better functional programming / pythonic ways of approaching this problem?

\$\endgroup\$
0

4 Answers 4

4
\$\begingroup\$

For the sake of the review, let us ignore the fact that there is both a sum (from Python 2.3) and statistics.mean (from Python v3.4), and analyse your code:

  • Good style in general – You seem to be following PEP8, and that is good
  • Some bad names – Read out stuff like grades_sum(grades), it reads like do the grades sum of grades. What is a grades sum versus an ordinary sum? On the other hand sum(grades) reads similarily as do the sum of grades. It has a natural flow, which we want to aim for. In addition when looking at the function it doesn't care whether we're adding grades or whatever else which can be added together
  • OK, code of functions – Nothing really magic happens in either function. They are straight forward, and you don't do anything extra (with exception of ignoring the predefined sum and mean. Not to many variable, and the concern for each function is clear
  • Be wary of the / divider in Python 2.x – This operator is somewhat unclear in Python 2.x, as it can be using integer division (and floor'ing the result) or change the end result into a float. See PEP238 for full discussion, but if you want true division when using / (i.e. to get float results consistently (if I've understood it correctly)) use from __future__ import division, and use // when you want the division floor'ed. Alternative do as you did, use float(divisor) to force it to become a float
  • Good print, but can be better – It is to easy to just print numbers in code, which you at some point will wonder: What was that number?. It's better to get used to a good code template like: print('Average of grades: {:,.2f}'.format(grades_average(grades)) or similar. This prints your value with a leading text, and let the float argument be printed with 2 decimals

When all this is said and done, read the documentation or do searches like "python sum" or "python mean" before reinventing the wheel.

\$\endgroup\$
4
\$\begingroup\$

In Python, there is a predefined function sum. This completely negates your need for grades_sum(scores).

def grades_average(grades):
    return sum(grades) / float(len(grades))

Also, you do not need to cast len(grades) to float if you are using Python 3.

\$\endgroup\$
8
  • 1
    \$\begingroup\$ Doesn't your comment about float differ whether the language is Python 2 or 3? \$\endgroup\$ Commented Oct 7, 2015 at 2:20
  • \$\begingroup\$ Also, if the language is Python 3.4 there is statistics.mean in the STL, which should replace some or all of the code for grades_average. \$\endgroup\$ Commented Oct 7, 2015 at 2:24
  • \$\begingroup\$ @Monkey No, I tested them both in IdeOne. I have only done a little bit of programming with Python, so I just knew about these points. \$\endgroup\$
    – user34073
    Commented Oct 7, 2015 at 3:13
  • 2
    \$\begingroup\$ But I am fairly sure int / int result is int in Python 2 if you do not specify "from __future__ import division". The author I assume would want a float result, so in Python 2 the way to do that without using the "future" module backport is to cast dividend or divisor as float. \$\endgroup\$ Commented Oct 7, 2015 at 3:41
  • 2
    \$\begingroup\$ I can confirm that on plain Python 2.7 the float cast is necessary. \$\endgroup\$ Commented Oct 7, 2015 at 10:12
1
\$\begingroup\$

As already mentioned, you should at least start by using Python's built-in sum function and could even look at the statistics module as someone else mentioned. See my example below:

>>> from statistics import mean
>>> grades = [100, 100, 90, 40, 80, 100, 85, 70, 90, 65, 90, 85, 50.5]
>>> sum(grades)
1045.5
>>> mean(grades)
80.42307692307692
>>>

However, this will only teach you about Python (version 3 in my example) --not make you more familiar or proficient in the functional paradigm. Learning both is fine, but I would not recommend Python 2/3 as an ideal language for this (i.e. functional programming proficiency) task.

You should look at languages that were designed with the functional paradigm in mind from the outset. Some I've used myself include Racket (formerly Scheme), which is a dialect of Lisp, and SML (Standard ML). There're more, so be sure to pick one of your interest. Just keep in mind that, although Python has support for some functional features (e.g. lambdas, and in a very limited way), it is not primarily a functional programming language, which is what you should be using based on your stated goal.

\$\endgroup\$
1
\$\begingroup\$

Why name it grades_average? Nothing about it is particular at all to grades. If there was a particular algorithm for your grades that would make sense, but you just have a normal mean distribution calculation. Name it average or mean, since it can be used for any arbitrary list of numbers.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.