I love python for a number of reasons. Brevity is one of them. Readability is another. However writing readable concise code can take some time to getting used to. This post discusses some code snippets especially in the context of some of the comparisons done between python and clojure – another language which excels at brevity and shares yet another feature with python, ie. people either love or hate its syntax, they are rarely indifferent to it.
Please note : The intent of this post is not to compare LOC of python with other languages. It is meant to demonstrate python code implementation which helps describe the capabilities of python in terms of writing clean, concise, readable code. This post continuously refers to other posts and may require you to read the referred posts in conjunction with this post to get maximum value.
Code and ceremony
The post Java vs Clojure – Lets talk ceremony! describes a simple problem which requires 28 LOC in Java and 1 or 9 in clojure. It is a simple logic which creates a list, populates it with four values (two of them identical) and creates a list with unique items. There are two alternative clojure implementations, one in 1 line of code and another in 9 – the former using a built in construct in the language which especially helps to write a more concise logic, and the latter by writing code similar to the Java code. Without any further ado, here are the two alternative python implementations
a. By using built in capabilities – In this case we use the set collection
1 | print set(("foo","bar","baz","foo")) |
b. Now here’s where we will not use a built in operator which automatically chooses the unique elements but again write code similar to the java code. This code is as follows :
1 | print reduce(lambda x,y: x + [y] if y not in x else x ,("foo","bar","baz","foo"),[]) |
There – both of them are exactly one line long.
Project Euler solutions
The post Python vs Clojure – Evolving refers to many sample python implementations solving some of the problems documented on project euler site. We shall revisit these python implementations here.
a. Find all numbers dividable by 3 or 5 in 0 < x < 1000:
In this case the clojure code is 4 lines long where as the python implementation is 3 lines long
1 | print sum(i for i in range(1,1000) if i%3 == 0 or i%5 == 0) |
Again the implementation is exactly 1 line long – no lambdas, no filters etc.
b. Get the sum of all even Fibonaccis below 4 mill.
The suggested python implementation is about 17 lines long. The implementation below 7.
1 2 3 4 5 6 7 8 9 | from itertools import takewhile def fib(): x,y = 1,1 while True : x,y = y,x+y yield x print sum(i for i in takewhile(lambda x : x < 4000000,fib()) if i%2 == 0) |
c. Finding Palindromes
The suggested python solution uses about 23 lines of code, to 6 in clojure and takes 15 seconds almost 300% slower than the clojure code (emphasis from the post referred to).
Here’s another alternative implementation.
1 | print max(x * y for x in xrange(100,1000) for y in xrange(100,1000) if str(x*y) == str(x*y)[::-1]) |
Again if you notice – exactly one line of code. And incidentally on my notebook it clocks in about 0.85 seconds which makes the clojure implementation about 470% slower than the python implementation. (emphasis mine)
Top Rank Per Group
In yet another post Python vs Clojure – Reloaded, the author discusses the Rosetta Top Rank Per Group implementation of python. Unsurprisingly the python implementation uses 11 lines of code (not including the initialisation) compared to clojure’s 6.
One of the commenters suggests an eminently readable and simple python solution in about 6 lines of code. The code snippet is as follows
1 2 3 4 5 6 7 8 9 10 11 | from itertools import groupby from operator import itemgetter data = [dict(name="Tyler Bennett", id="E10297", salary=32000, department="D101"), ...] department = itemgetter('department') for dep, persons in groupby(sorted(data, key=department), department): print "\nDepartment", dep print " Employee Name Employee ID Salary Department" for person in sorted(persons, key=itemgetter('salary'): print "%(name)-15s %(id)-15s %(salary)-15s %(department)-15s" |
An alternative far less readable solutions which shaves off one more line but certainly not preferred to the solution above (am just listing it since it shaves off the step of having to create an intermediate data structure) is
1 2 3 4 5 6 7 8 9 10 | import operator from itertools import groupby data = [('Employee Name', 'Employee ID', 'Salary', 'Department'),....] print reduce(lambda x,y : x + y, (('\nDepartment %s\n Employee Name Employee ID Salary Department ' % dept + reduce(lambda x,y : x + ("\n " + "%-15s " * len(data[0]) % y), sorted(recs, key=lambda rec: -rec[-2])[:3],'')) for dept, recs in groupby(sorted(data[1:],key=operator.itemgetter(3)), lambda x : x[3])),'') |
Some might wonder whether I am joining multiple lines of code into one just to reduce the line count. The code is consistent with the idiomatic usage of python and also with the way python list comprehensions are documented in the formal python proposal for list comprehensions PEP 202 : List Comprehensions. Besides python is a whitespace sensitive language and the compiler disallows multiple lines of code in one line without using the ‘;’ separator which I have most definitely not used in the suggested solutions.
PS: There’s of course an interesting image at the end of the post Python vs Clojure – Reloaded indicating the perception of how clojure code speaks for itself
. The reason I mention it is that I believe if one is expressing a strong opinion as the one reflected by the picture, one better be far more careful and thorough with verifying the veracity of the assertions appropriateness of the samples compared to. Let me clearly state that I do not know that the clojure loc compared to is an appropriate target so do not infer this post to be a Python vs Clojure LOC as much as a post which emphasises that Python is a good vehicle to write concise readable code. FWIW I am learning clojure and look forward to building more competence with it.
Update: There is another nice post by Stephan Schmidt – Anatomy of a Flawed Clojure vs. Scala LOC Comparison which does reflect an opinion in the context of Scala and a post authored on the same blog as the ones I refer to above.
Related posts: (Automatically Generated)


Nice post, LOC comparisons are tricky, but done right we can all learn something.
Cheers
Stephan
Concerning the Java solution: Using HashSet makes the solution a one-liner in Java too (someone mentions this in the comments).
Cheers
Stephan
Stephan,
Yes, am in full agreement on the LOC comment. On the Java HashSet matter, yes thats what a good java programmer would want to do. Though even under a shorter code, the implication of the ceremony (boilerplate) will not be lost. Again goes back to my point of selecting appropriate pieces of code to draw inferences and learnings from.
Dhananjay
@Stephan: I can’t see the one-liner here due to the ceremony stuff. Can one have less LoC (in Java) than this?
2
3
4
5
6
class Main {
public static void main(String[] args) {
System.out.println(new ArrayList(new LinkedHashSet(Arrays.asList("foo", "bar", "baz", "foo"))));
}
}
@Dhananjay: I think you’re solution with Python’s “set” is not comparable to the task described in Lau Jensens ceremony blog post, since “set” doesn’t care about the order of the elements. But Lau’s task was to only “remove duplicats”, i.e. list as input, list as output, no change in the order of the elements left.
Your algorithm changed the order to ‘baz’, ‘foo’, ‘bar’, which would remove the duplicates and changes the order. The same would be true for the Java solution if I wouldn’t use LinkedHashMap instead of HashMap.
Thanks for that nice blog post! I really enjoyed reading it
Bernd,
I reread Lau’s post and it isn’t obvious whether he wanted the ordered semantics (per the text), though the code does reflect the ordered semantics. So assuming ordered semantics is required, the second solution would be the way to go.
You can also read another great article titled ” The fate of reduce() in Python 3000 ” http://www.artima.com/weblogs/viewpost.jsp?thread=98196.
Though i could never understand what is so great with one liners except to look cool in the game of code golfing.
1)Does it increase readability? I don’t think so. IMHO if one can write concise code it’s good, but counting lines never looked like a criteria to judge a piece of code to me.
2)usage of Lambdas. Certainly there may be situations where using lambdas may make code more readable. But just like design patterns they should not be used just to look cool.
Python’s awesomeness lies in the fact that it allows you to write code which will be as readable as in pseudocode, or in another words executable pseudocode.
The question one should ask himself while writing code in python should be, is this the way i will explain what the code is trying to do in pseudocode, also does the concept of one liner makes sense in pseudocode as well.
Ashish,
I look forward to continuing to use reduce in Python 3000 from the functools package, as much as I am likely to also want to use functools.partial. The issue isn’t coolness, it is appropriateness. There are a number of scenarios where as an example, writing a separate function and passing it to another which uses it in a for loop, or in a map / apply / reduce function helps separate different concerns. I fully believe using these capabilities to achieve separation of concerns (where appropriate and applicable) is extremely helpful in terms of improving maintainability and testability of code. In fact in a larger number of cases, I have observed that using functions through such functional constructs helps substantially improve testability. Maybe a 100 line function looks cool when it is similar to a 100 line pseudocode, but break it down and you are likely to get a much better testable software and concise code even though the code may not be as obvious. Decomposition is a matter of taste, judgement and consistency with a set of priorities. I don’t think there is one way which is necessarily superior to another.
Python’s awesomeness lies in the fact that it allows you to write code which is consistent with your design thoughts, philosophies and temporal objectives. It doesn’t require you to choose between object oriented, functional or for that matter even the traditional procedural programming. That diversity is what makes it healthy.
Having said that I do believe, there are likely to be some situations where our opinions may differ.
Hi Dhananjay,
i agree with most of what you just said. However i would like to state that the readability of code becomes much more important, especially in the case of high level duck typed languages such as python as compared to other middle level languages such as c++ etc.
As one tends to give more freedom of expression to programmer, the code also reflects much more to his state of mind then some one else may understand.
Interesting.
[Oops!! submit button got clicked before the response was completed]
Hi Dhananjay,
i agree with most of what you just said. However i would like to state that the readability of code becomes much more important, especially in the case of high level duck typed languages such as python as compared to other middle level languages such as c++ etc.
I agree on how one decides upon the right mixture of brevity,readability and code maintainability can vary from person to person. I have seen excessive usage of one liners in some high level language code snippets, that’s not wrong at all as long as the programmer has been able to keep the right balance between the code being concise and readable. So many times incorrect usage of functional constructs like lambda,reduce without maintaining that delicate balance makes code smelly, though not always.
Above all we pythonistas should always remember ” The Zen of Python ”
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Precisely the point I made in the first four sentences of this blog post.