Python is, in my opinion, one of the easiest and most versatile languages in computer science. If you write python code correctly, it is difficult to differentiate a python code from pseudo-code. But sometimes, in the process of writing the most beautiful python code, most developers forget one thing: the execution speed of the code.
You can write code that is so readable and a layman can confuse it as English written by someone with bad grammar skills, yet it is understandable. But that code takes more than 300ms to run. That might not be that much of a delay but in the programming world, it is a serious problem.
On the other hand, one can write the same code in a different idiom that it takes less than 10ms to run. But, even expert python developers undergo a hard time understanding it.
It is thus very imported, for a developer to strike a balance between these two extremes. These kinds of code are known as Idiomatic Code in the industry.
Idiomatic Code, by definition, is a code that does a common task in a common way for your language. In other words, idiomatic code is any code that is easy to read and at the same time, is extremely efficient.
I follow Raymond Hettinger (@raymondh) a lot on twitter, he is one of the core developers in the Python community and he has contributed a lot of code in the Python repository to make the python language more idiomatic.
In this blog, I will go through some of the techniques that will help you improve your python code. Starting with:
a. range()
Let's start from the obvious, say you need to iterate from 2 to 10. So if you're like an absolute beginner you might write something like this:
for i in [2,3,4,5,6,7,8,9,10]:
print(i)
Something like this works and is very understandable, it is not a scalable approach. What if you want to loop through 2 to 2 million.
In situations like this, you can use the range(stop)
or range(start, stop, [step,])
built-in function.
the range function automatically generates the list for you. For example, you can rewrite the above code as:
for i in range(2, 11):
print(i)
Notice how I wrote start from 2 and end at 11 and not 10. This is because the range function loops till stop - 1
. There is one more parameter in range function other than the start and stop, that is the step. Step determines how many numbers the range have to skip.
Let's say you need to print all even numbers from 2 to 10, in that case, the skip parameter will be 2. By default, it is 1.
for i in range(2,11,2):
print(i)
# OUTPUT: 2 4 6 8 10
Now let's say that you need to loop through a list. With the knowledge of range(), you might do this:
cloths = ['shirt', 'hat', 'socks', 'shorts']
for i in range(len(cloths))
print(cloths[i])
But in python, there is a better way:
cloths = ['shirt', 'hat', 'socks', 'shorts']
for cloth in cloths
print(cloth)
b. zip()
Let's say you have two lists, colour and cloths, of different sizes and you want to pair them until the smaller list is over. In this case, you can write a code like this:
colours = ['pink', 'red', 'green']
cloths = ['shirt', 'hat', 'socks', 'shorts']
n = min(len(colours), len(cloths))
for i in range(n):
print(colours[i], cloths[i])
# OUTPUT
# pink shirt
# red hat
# green socks
Which is good, but you can also use the in-built function zip(*iterables)
the best thing about this function is that you can pass any number of lists, not just two.
Let me rewrite the above code and then explain to you how zip works.
colours = ['pink', 'red', 'green']
cloths = ['shirt', 'hat', 'socks', 'shorts']
for colour, cloth in zip(colours, cloths):
print(colour, cloth)
# OUTPUT
# pink shirt
# red hat
# green socks
You might have guessed, zip takes any number of lists and returns another list that contains one element from each list. As you can see, both version produces the same output but the second one looks cleaner.
c. reversed()
If you want to loop over a list in reverse order, the traditional method was something like this.
cloths = ['shirt', 'hat', 'socks', 'shorts']
for i in range(len(cloths)-1, -1, -1):
print(cloths[i])
# Output
# -------
# shorts
# socks
# hat
# shirt
But with Python, you can use the builtin function called reversed(). Take a look at this example:
cloths = ['shirt', 'hat', 'socks', 'shorts']
for cloth in reversed(cloths):
print(cloth)
# Output
# -------
# shorts
# socks
# hat
# shirt
The second one is cleaner and faster than the first one.
d. enumerate()
You want to loop through a list along with the index. It's pretty straight forward in traditional programming:
cloths = ['shirt', 'hat', 'socks', 'shorts']
for i in range(len(cloths)):
print(i, cloths[i])
# Output
# -------
# 0 shorts
# 1 socks
# 2 hat
# 3 shirt
But there is a cleaner and more efficient way in python:
cloths = ['shirt', 'hat', 'socks', 'shorts']
for i, cloth in enumerate(cloths):
print(i, cloth)
# OUTPUT
# -------
# 0 shorts
# 1 socks
# 2 hat
# 3 shirt
e. sorted()
You need to loop over a list in sorted order, instead of running a sorting algorithm, you can use the sorted() built-in method.
nums = [2,3,1,5,2]
for i in sorted(nums):
print(i)
# OUTPUT
# ------
# 1
# 2
# 2
# 3
# 5
The python sorted function uses Tim Sort with an average complexity of n*log(n)
For reverse sorting, you can use the attribute sorted(nums, reverse=True)
What you want to sort a list of strings.
cloths = ['shirt', 'hat', 'socks', 'shorts']
for cloth in sorted(cloths):
print(cloth)
# OUTPUT
# ------
# hat
# shirt
# shorts
# socks
It will sort based on letters, but what if you want to sort based on length of the string, you can do that with key attribute. For example:
cloths = ['shirt', 'hat', 'socks', 'shorts']
for cloth in sorted(cloths, key=len):
print(cloth)
# OUTPUT
# ------
# hat
# shirt
# socks
# shorts
So that was 5 techniques using with you can make your python code more idiomatic.