I recently did a talk at EPAM on hidden gems in Python. Here are the slides from the talk, along with the explanations.
Hidden gems are those small features that help making coding in Python easier and more fun. We are not talking about the big features that make the headlines, but rather small things that we can use day to day to solve small problems.
I would also like to know what are your Python hidden gems? Mention them in the comments at the bottom.
Note that you have to be a subscriber and signed in to view the slides and to add comments. If you are reading this via email, you are already a subscriber. Otherwise, become a subscriber below.
Consider the problem statement above. Below is the code to solve it in Python
Here are the various conveniences that Python provides us while solving this problem:
- The ability to index from the end using
word[-1]
- Easily getting subsets using slice notation,
word[:-1]
- Easily check if an element is a present in a collection using the
in
operator - List comprehensions that allow us to quickly transform an iterable in a simple way
None of these features is groundbreaking, but it makes writing Python code a pleasant experience.
While the features above are well known, I will now share some of my favourite other hidden gems in python.
Iteration Unpacking
One of the super convenient features is iteration unpacking. That is, taking an iterable and assigning separate variables to each element. Consider the code below where we split a string and get two fields.
name = "Siddharta,Chennai"
data = name.split()
print(name[0])
print(name[1])
Since split()
returns a list, we need to refer to each field using the index [0]
or [1]
. Not very readable!
Now look at the code below
On the left hand side we have name, city
. This will 'unpack' the list and assign name
variable to the first element and city
variable to the second element. Super convenient!
But wait, there's more!
You can also use *var
to assign the rest of an iterable to a variable. In the code above, the first
variable gets Anjali
while rest
gets a list of every other key. (Keep in mind that dict
objects are iterable - they iterate through all the keys)
But that's not all! What if I wanted both the key and value of the first entry in the dictionary?
Well, we can use the .items()
method to get an iterable of key-value pairs, then unpack that. Look at this
First we unpack the iterable, then the code (name, subject)
unpacks the key-value tuple element. Yes, unpacking can be nested!
Itertools
Well the itertools
module isn't 'hidden' as such, but it's still very powerful and one of my favourites. I've written about this before, but it doesn't hurt to repeat it.
90% of the time, you don't need nested loops or the range() function
Here is an example: Below is the problem statement of the divisible sum problem.
If you google the solution, you will get an answer like this.
This code uses an implementation from Java or C, languages that don't have the expressiveness of Python.
When you actually use all the Python features at our disposal, this is what we get
That's right - its two lines of code. Here is what we take advantage of:
- The
combinations
function initertools
will directly give us all pairs of elements as a tuple. No need to loop and calculate it - The
sum
function works on any iterable, so we can directly add up all the elements in the tuple. - Finally, list comprehensions allow us to easily do transforms and filters on the iterable
Fifteen lines of code, with three levels of nesting, transformed into two lines and no nesting. (you can make it a one-liner if you really want, but I also value readability).
Brilliant!
Another example: You need to read and process all files in a directory. Think you need nested loops? Nope. Just use the chain()
function.
itertools
is chock full of functions that can make life really simple for you. Just check out the documentation for more ideas of things you can do.
zip()
The zip()
built-in function is the function that I miss the most when working in another language. It's such a simple function, and in the early days I used to even question what was the use of this function?
zip()
takes two (or more) iterables and allows you to iterate them together - much like a zipper in real life. You'll get the first element of both iterables, then the second element of both, third element of both and so on.
Needing to iterate two independent iterables together sounds like an edge case scenario, but it just comes up so often in day to day work.
But it's not just iterating two separate iterables.
Say we need to iterate a list two elements at a time. So if I have a string "Today is a sunny day", I need to generate [('Today', 'is'), ('is', 'a'), ('a', 'sunny'), ('sunny', 'day')]
The naive way is to use range()
, but this can be easily done in a much cleaner way with zip()
or even the newly added function pairwise()
from the itertools
module.
any() and all()
I have recently written a whole article about any
and all
, so click this link to read up on these two built-ins.
The match statement
Again, this is one that I covered extensively in a previous talk. You can find the slides of that talk here.
Summary
So that's a wrap of my five Python "hidden gem" features. What are your favourite features in Python? Mention them in the comments below 👇🏾
Did you like this article?
If you liked this article, consider subscribing to this site. Subscribing is free.
Why subscribe? Here are three reasons:
- You will get every new article as an email in your inbox, so you never miss an article
- You will be able to comment on all the posts, ask questions, etc
- Once in a while, I will be posting conference talk slides, longer form articles (such as this one), and other content as subscriber-only