⭐ Definition: A Python one-liner is a snippet of code that solves a problem in a single line.
Want to learn to write Pythonic code? This article will show you the top 10 most elegant Python one-liners. You can also find a follow-up article with 38 clever one-liners on the Finxter blog:
👉 Tutorial: Level Up Your Python With These 38 Clever One-Liners
Let’s dive into the code! Here is an overview of all the Python one-liners in this article – ranked from easiest to hardest. Don’t worry if you don’t understand them now. I’ll explain them in detail below.
# 10. Palindrome Python One-Liner phrase.find(phrase[::-1]) # 9. Swap Two Variables Python One-Liner a, b = b, a # 8. Sum Over Every Other Value Python One-Liner sum(stock_prices[::2]) # 7. Read File Python One-Liner [line.strip() for line in open(filename)] # 6. Factorial Python One-Liner reduce(lambda x, y: x * y, range(1, n+1)) # 5. Performance Profiling Python One-Liner python -m cProfile foo.py # 4. powerset Python One-Liner lambda l: reduce(lambda z, x: z + [y + [x] for y in z], l, [[]]) # 3. Fibonacci Python One-Liner lambda x: x if x<=1 else fib(x-1) + fib(x-2) # 2. Quicksort Python One-liner qsort = lambda L: [] if L==[] else qsort([x for x in L[1:] if x< L[0]]) + L[0:1] + qsort([x for x in L[1:] if x>=L[0]]) # 1. Sieve of Eratosthenes Python One-liner lambda n: reduce( (lambda r,x: r-set(range(x**2,n,x)) if (x in r) else r), range(2,int(n**0.5)), set(range(2,n)))
Let’s dive into each of those Python one-liners.
Check out my new Python book Python One-Liners (Amazon Link).
If you like one-liners, you’ll LOVE the book. It’ll teach you everything there is to know about a single line of Python code. But it’s also an introduction to computer science, data science, machine learning, and algorithms. The universe in a single line of Python!
The book was released in 2020 with the world-class programming book publisher NoStarch Press (San Francisco).
Publisher Link: https://nostarch.com/pythononeliners
One-Liner #10: Check If a String is a Palindrome
What is a palindrome? A palindrome is a sequence of characters or numbers “which reads the same backward as forward, such as madam or race car or the number 10201” (Wikipedia).
💬 Challenge: Write a Python one-liner that returns the integer 0, if the sequence is a palindrome. Otherwise, return -1.
# THE DATA phrase = "anna" # THE ONE LINER is_palindrome = phrase.find(phrase[::-1]) # THE RESULT print(is_palindrome) # 0 (if it wasn't a palindrome, the result would be -1)
This Python one-liner uses two tools to achieve the goal: the find()
method and slicing.
String Find
The string.find()
method returns the start index of a given subsequence within a sequence.
For example, you can call y.find(x)
on any string y
in Python.
- If the string
y
contains the stringx
, the method returns the start index of the stringx
withiny
. - If the string
y
does not contain the substringx
, it returns-1
.
Slicing
Slicing is a Python-specific concept for selecting a range of values from sequences such as lists or strings. Slicing notation is [start:stop:step]
. It selects a sequence starting at index “start
” (inclusive) and ending at index “stop
” (exclusive).
The “step
” parameter defines the number of characters your slice skips before selecting the next one. By default, it is 1
. Setting step=2
means that your slice consists of every second character.
👉 Recommended: If you want to become a true master of slicing, download my ebook “Coffee Break Python Slicing” for free.
A negative step size means the slice is selected “backward”, i.e., from right to left. In this way, the one-liner reverses the string by slicing phrase[::-1]
.
Why reverse the string at all? Easy: If the original string contains the reversed string, it is a palindrome. Think about it for a moment and enjoy this wonderful concise Python one-liner.
One-Liner #9: Swap Two Variables
💬 Question: Suppose you have two variables a
and b
. You want to assign the value of a
to variable b
and the value of b
to variable a
. How do you do this in Python?
# THE DATA a = "hello" b = "bye" # THE ONE-LINER a, b = b, a # THE RESULT print(a) # bye print(b) # hello
This is a nice little trick of the Python programming language. The standard way of doing this in other languages is to create a third “container” variable that does nothing but store the value of a
for a moment while both variables a
and b
have the same value:
# THE UGLY THREE-LINER USED IN OTHER LANGUAGES c = a a = b b = c
Two lines saved while improving readability – not bad for a one-liner!
One-Liner #8: Sum Over Every Second List Value
💬 Question: Given a list of values of either integers or floats, we want to sum over all the values with an even index. That is, values with index 0, 2, 4, 6, 8 etc. How do we do this in a single line of code?
# THE DATA stock_prices = [23, 24, 26, 29, 41, 29, 35] # THE ONE-LINER res = sum(stock_prices[::2]) # THE RESULT print(res) # 125
This one-liner uses advanced slicing notation. Recall that slicing selects a range of values from a list using the notation [start:stop:step]
.
The first index of the slice is “start
” (inclusive) and the last index is “stop
” (exclusive).
As you may have guessed, the third parameter “step
” defines the step size. That is, how many characters from the original sequence are skipped before selecting the next character. Setting step=2
means your slice will consist of every other character.
👉 Recommended: Get the free slicing book.
Finally, the sum()
operation takes any iterable and sums over all values in it. First, The slice selects every other value and then sum()
adds them together.
One-Liner #7: Read Lines From a File and Store Them in a List
Your program must communicate with the outside world to have any impact. One way of doing this is to use the file system for input and output.
💬 Question: How can you read all the lines from a file in one line? As a bonus, how can you get rid of trailing whitespaces while reading the lines (e.g., the newline character ‘\n
’)?
For this, I’ve saved The Zen of Python in the file zen_of_python.txt
. If you don’t know what it is, type import this
into your Python terminal and have a look at the output.
# THE DATA filename = 'zen_of_python.txt' # THE ONE-LINER lines = [line.strip() for line in open(filename)] # THE RESULT print(lines)
Output:
['The Zen of Python, by Tim Peters',
'Beautiful is better than ugly.',
'Explicit is better than implicit.',
...
"Namespaces are one honking great idea -- let's do more of those!"]
Complex Python one-liners are built upon simpler ones. You have to master the simple ones first to understand the more complex ones.
This one-liner is simple and very important. We create a new list ‘lines
’ using a list comprehension. Then we store all lines from the file as separate string values.
List comprehensions are a compact way to create lists. If you want to master list comprehension once and for all, read our in-depth tutorial. The simple formula for them is [ expression + context ]
.
- Expression: What to do with each list element?
- Context: Which list elements to select? This consists of an arbitrary number of for and if statements.
The one-liner uses the expression line.strip()
. The string method strip()
removes the leading and trailing whitespace (e.g., the newline character ‘\n
’) from each line the context returns.
The context iterates over the file object returned by open(filename)
. It specifies the objects on which the expression will be performed. In this case, it selects all the lines (string objects) from the file ‘zen_of_python.txt
’.
💡 Note: whilst this one-liner works, it is best practice to close files once they have been opened. The with
statement is the most Pythonic way to do this. Once you exit the with
block, the file is automatically closed.
with open('zen_of_python.txt') as f: lines = [line.strip() for line in f] print(lines)
Output:
['The Zen of Python, by Tim Peters',
'Beautiful is better than ugly.',
'Explicit is better than implicit.',
...
"Namespaces are one honking great idea -- let's do more of those!"]
One-Liner #6: Calculate the Factorial Function (n!)
💬 Question: How to calculate the factorial function in Python?
This is a fun challenge that is often asked in Python programming interviews. There are many ways of solving this problem, but why not impress the interviewer with a beautiful Python one-liner solution?
# THE DATA from functools import reduce n = 100 # THE ONE-LINER factorial = reduce(lambda x, y: x * y, range(1, n+1)) # THE RESULT print(factorial) # 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
The one-liner uses the reduce()
function.
💡 The reduce
function takes two arguments: a function and a sequence. It takes two values from the sequence and combines them according to the function argument. Then it repeats this procedure until only one value is left and returns that value.
It’s that simple.
In Python 3, the reduce function is not a built-in function (but it is in Python 2). So you have to import it from the functools
library.
The one-liner defines an anonymous function using the lambda expression. The lambda function takes two arguments, x
and y
, and multiplies them together – x * y
. In this way, the reduce
function multiplies all values in the sequence with each other.
Instead of assigning n
before we write our one-liner. We can define our function to work with any n
by adding a lambda call before reduce
.
Factorial = lambda n: reduce(lambda x, y: x * y, range(1, n+1)) print(Factorial(3)) # 6 print(Factorial(10)) # 3628800 print(Factorial(20)) # 2432902008176640000
One-Liner #5: Profile a Python Script
Performance optimization is important for all applications. This is especially true when you start working on bigger projects.
Profiling is the term we use when we measure the performance of a program.
The Python documentation says “A profile is a set of statistics that describes how often and for how long various parts of the program executed”.
This one-liner can be executed in the terminal without opening Python. Let’s say, you want to profile the Python script ‘foo.py
’.
$ python -m cProfile foo.py
The one-liner uses the cProfile application to profile the performance bottlenecks of ‘foo.py
’. You don’t have to execute the Python script to profile it – the cProfile application does it for you. Then, it tracks statistics (e.g., which functions took the most amount of time) and outputs these statistics to the console.
Here is an example output of such a profiling call (source).
197 function calls (192 primitive calls) in 0.002 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.001 0.001 <string>:1(<module>)
1 0.000 0.000 0.001 0.001 re.py:212(compile)
1 0.000 0.000 0.001 0.001 re.py:268(_compile)
1 0.000 0.000 0.000 0.000 sre_compile.py:172(_compile_charset)
1 0.000 0.000 0.000 0.000 sre_compile.py:201(_optimize_charset)
4 0.000 0.000 0.000 0.000 sre_compile.py:25(_identityfunction)
3/1 0.000 0.000 0.000 0.000 sre_compile.py:33(_compile)
The profiler keeps track of the number of calls each function makes and how long each function runs (its latency). These statistics will help you greatly when optimizing your code. They have certainly helped me a lot.
One-Liner #4: Write a Function that Returns the Powerset of a Set
A powerset is the set of all subsets of a given set.
Unfortunately, it’s not possible to define a set of sets in Python. So our one-liner creates a list of lists.
Sets can only contain immutable (i.e., hashable) objects. Python uses the hash value of an element when checking if it’s a member of a set. This makes the operation incredibly fast. Doing the same with a list is much slower.
This is one advantage sets have over lists.
👉 Set vs Lists — Performance Difference
For more info on hashing, check out this section of our article on Python Dictionaries.
# THE DATA from functools import reduce dataset = {1,2,3} # THE ONE-LINER f = lambda l: reduce(lambda z, x: z + [y + [x] for y in z], l, [[]]) # THE RESULT print(f(dataset)) # [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
The source code is modified from this article.
The one-liner shows an elegant way to solve the problem of calculating the superset. Still, I have to admit it’s hard to understand.
To aid your understanding, let’s first write out a powerset function over several lines. But before we do that, we need to understand the process of creating a powerset.
Creating a Powerset Manually
Recall that a powerset is the set of all subsets of a given set.
By definition, every set contains the empty set as a subset. Thus a powerset is never empty – it always contains at least the empty set.
The most basic powerset is [[]]
and this is the powerset of []
. So any code we write will use this basic powerset as its foundation.
Let’s create the powerset of {1}
. From above, we know it contains the empty set []
. The only element left is 1. Thus the powerset is [[], [1]]
.
The powerset of {1, 2}
follows a similar pattern. It contains []
and [1]
like above. But also contains [2]
. Lastly, as is the case with every set, the entire set is classed as a subset. So the powerset also contains [1, 2]
. The final answer is [[], [1], [2], [1, 2]]
.
We will now write the process above as an algorithm. Let’s start with pseudo-code and build the powerset of {1, 2}
. The process is adding each element in the set, to all the elements already in the powerset.
Remember that you cannot have a set of sets in Python, so our powerset will be a list of lists.
my_set = {1, 2} # Our powerset starts as a list containing the empty list powerset = [[]] # Take first value of my_set and add it to every list in powerset first_value = 1 # Only list in powerset is [], so we have one sum to do [] + 1 = [1] # The result of the sum is the next subset to include in powerset # Append result to powerset powerset.append([1]) # Our powerset is now powerset = [[], [1]] # Take next value of my_set and add it to every list in powerset next_value = 2 # Lists in powerset are [] and [1], so we have 2 sums to do [] + 2 = [2] [1] + 2 = [1, 2] # Append each result to powerset powerset.append([2]) powerset.append([1, 2]) # And we have powerset = [[], [1], [2], [1, 2]] # We have run out of values in my_set and so are finished
Creating a Powerset with Code
We will follow the pseudo-code above but will make one change. Instead of using append
we are going to use the list concatenation operator +
# These are the same powerset.append([1]) powerset + [[1]]
We know that a powerset is a list of lists. We want to append the values in my_set
to each list in this list of lists. We do this until we run out of values in my_set
. Writing this as a for
loop, we get
for lst in list_of_lists: lst.append(value)
This is the same as
for lst in list_of_lists: lst + [value]
To make our code return a list of lists, we add a couple of lines before and during our for
loop
# Initialise empty list final_list_of_lists = [] # Do our iteration for lst in list_of_lists: next_list = lst + [value] # Append value we want to our final_list_of_lists final_list_of_lists.append(next_list)
Since lst.append(x)
is the same as lst + [x]
, we can write it as a list comprehension and achieve the same result in 1 line
[lst + [value] for lst in list_of_lists]
Lastly, on each iteration, we don’t want to lose the current elements in our powerset. So we add the entire list_of_lists
to the start
list_of_lists + [lst + [value] for lst in list_of_lists]
Let’s write this as a function with a very descriptive name
def add_value_to_every_list_in_list_of_lists(list_of_lists, value): """ Given a list_of_lists, return a list that contains the original list_of_lists and each list with value appended to it. e.g. # Add 3 to every list in [[], [1], [1, 2]] and return original # list of lists >>> add_value_to_every_list_in_list_of_lists([[], [1], [1, 2]], 3) [[], [1], [1, 2], [3], [1, 3], [1, 2, 3]] """ return list_of_lists + [lst + [value] for lst in list_of_lists]
To create a powerset, we apply this function recursively to every value in my_set
. We start with the empty set as the only element in our list of lists.
def powerset(my_set): """ Return the powerset of my_set """ # Initialise most basic powerset current_powerset = [[]] # Iterate over every value in my_set for value in my_set: # Recursively generate powerset. # Add next value to all elements of current_powerset, then # move onto next value current_powerset = add_value_to_every_list_in_list_of_lists(current_powerset, value) return current_powerset
Let’s test it out:
>>> powerset({}) [[]] >>> powerset({1}) [[], [1]] >>> powerset({1, 2}) [[], [1], [2], [1, 2]] # It works! >>> powerset({1, 2, 3}) [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
Now we’ll go back to the one-liner and show how it is equivalent to the functions above. We’ve replaced list_of_lists
with LoL to save space:
# One-liner f = lambda l: reduce(lambda z, x: z + [y + [x] for y in z], l, [[]]) # One-liner with the descriptive names we used above f = lambda my_set: reduce(lambda LoL, value: LoL + [lst + [value] for lst in LoL], my_set, [[]])
f = lambda my_set:
is the same asdef powerset(my_set):
- The first argument of
reduce()
is the same code asadd_value_to_every_list_in_list_of_lists(LoL, value)
- The
reduce()
function iterates through my_set. It applies the lambda function (argument 1) to each element in my_set (argument 2) and adds the result to a list. We define the starting list as[[]]
(argument 3).
One-Liner #3: Find the First n Fibonacci Numbers
What are the Fibonacci numbers? They are the values of the Fibonacci Sequence. The Fibonacci Sequence was created by the Italian mathematician “Leonardo of Pisa”. It is very popular because it has many applications in math, art, and biology (read more here).
👉 Recommended: Fibonacci in One Line Python
The sequence starts with the numbers 0 and 1. Each following element is the sum of the two previous elements.
# THE DATA n = 10 # THE ONE-LINER fib = lambda x: x if x<=1 else fib(x-1) + fib(x-2) # THE RESULT for i in range(n): print(fib(i)) """ 0 1 1 2 3 5 8 13 21 34 """
The one-liner computes the Fibonacci series recursively. It defines an anonymous function with one parameter x
to calculate the x
-th Fibonacci element.
The recursion base cases are x=0
and x=1
for which the Fibonacci numbers are 0 and 1, respectively. On top of that, the function calls itself to calculate the (x-1
)-th and (x-2
)-th Fibonacci numbers – and sums over both to calculate the x
-th Fibonacci number.
While this is an intuitive way of defining the Fibonacci series, it is very inefficient because of highly redundant function calls.
For example, the third Fibonacci number is calculated from scratch to find the fourth, the fifth, and the sixth Fibonacci number.
A much better way would be to store the third (and each subsequent) Fibonacci number in a list rather than recomputing it again and again.
Therefore, the function is very slow at calculating even a dozen Fibonacci values. Still, this one-liner serves an educational purpose and is readable and concise.
One-Liner #2: Write the Quicksort Algorithm
If you don’t know the quicksort algorithm, have a look at this video:
Now, let’s create a one-liner that runs this algorithm!
# THE DATA unsorted = [33,2,3,45,6,54] # THE ONE-LINER qsort = lambda L: [] if L==[] else qsort([x for x in L[1:] if x< L[0]]) + L[0:1] + qsort([x for x in L[1:] if x>=L[0]]) # THE RESULT print(qsort(unsorted)) # [2, 3, 6, 33, 45, 54]
The first thing the Quicksort algorithm (source) does is select a pivot element. In our code, it selects the first element, L[0]
, as the pivot.
Then, the algorithm moves all elements smaller than the pivot to the left side. And it moves all elements larger or equal to the pivot to the right side. This is repeated recursively for the left and the right lists.
Let’s suppose you create a new list as follows.
You put all elements that are smaller than the pivot to the left, the pivot in the center, and all elements that are larger or equal to the pivot to the right.
You would consider the resulting list to be a bit more sorted, right?
If the two sublists were already sorted, you would be finished. This is where the recursive call of qsort
comes into play. It takes over the problem of sorting each sublist by applying the same scheme of pivoting and recursion as above.
Here is the one-liner written in pseudo-code to make it easier to understand:
if L == []: return [] else: # Move all elements less than L[0] to the start return qsort([x for x in L[1:] if x < L[0]]) \ # Put L[0] after all elements smaller than it + L[0:1] \ # Move all elements greater than L[0] after L[0] + qsort([x for x in L[1:] if x >= L[0]])
One-liner #1: Write the Sieve of Eratosthenes
The Sieve of Eratosthenes is an ancient algorithm that finds all the prime numbers below a specified number n
. If you don’t know the algorithm, here is a very nice video from Khan Academy:
The idea is based on the fact that every number can be written as the product of prime numbers. This is called prime factorization.
For example, 30 = 2 x 3 x 5 and we say that the prime factors of 30 are 2, 3 and 5. A number is prime if its prime factors are 1 and itself. For example, the prime factors of 19 are 1 and 19. Thus 19 is prime.
You begin The Sieve of Eratosthenes by defining a number, n
. You wish to find all prime numbers up to and including n
. We do this by excluding all non-prime numbers below n
. This leaves us with only prime numbers.
You start with all numbers unmarked. If you come to an unmarked number, it is prime.
We start at 2 and see this is unmarked. Thus it is prime.
We now mark all multiples of 2 as ‘non-prime’. So 4, 6, 8, 10… are all marked as ‘non-prime’.
Next, we see that 3 is unmarked. So it is also prime. We now mark all multiples of 3 as “non-prime”. But 6 has already been marked as non-prime because it’s a multiple of 2. So we start marking non-primes from 3 ** 2 = 9
.
Generally, for an unmarked number x
, you mark all its multiples as non-prime starting from x**2
. Once you find an x
where x**2 > n
, you stop. The unmarked numbers you have left are all the primes up to n
.
In our code, we will ‘mark’ numbers by removing them from the set of all numbers from 2 to n. The ‘unmarked’ numbers are those that remain.
# THE ONE-LINER primes = lambda n: reduce( (lambda r,x: r-set(range(x**2,n,x)) if (x in r) else r), range(2,int(n**0.5)), set(range(2,n))) # THE RESULT print(primes(100) # {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97}
This one-liner is based on a StackOverflow answer.
It’s very elegant, but you need to invest some time to understand it. So let’s rewrite it as a function so that it’s easier to understand.
def sieve_of_eratosthenes(n): """ Return the set of all prime numbers below n """ # We want all primes in the range 2 to n all_nums = set(range(2, n)) # We start marking non-primes from x**2 # So only need to check numbers up to the square root of n nums_to_check = range(2, int(n**0.5)) # Write as a for loop for x in nums_to_check: # if x in all_nums, it has not been marked and so is prime if x in all_nums: # keep x and remove all multiples of x from x**2 onwards all_nums = all_nums - set(range(x**2, n, x)) # if x not in all_nums, it has been marked/removed and so is # not prime. Move onto next iteration without any action else: continue # Numbers remaining are all primes up to n return all_nums
This is much easier to understand than the one-liner thanks to the use of descriptive variable names, a for
loop and well-commented code.
But does it work? Of course it does!
>>> sieve_of_eratosthenes(10) {2, 3, 5, 7} >>> sieve_of_eratosthenes(37) {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31}
We’ll now slowly turn this into the one-liner.
One-liner broken down
# THE ONE-LINER primes = lambda n: reduce((lambda r,x: r-set(range(x**2,n,x)) if (x in r) else r), range(2,int(n**0.5)), set(range(2,n))) # Function name primes = # The input to our function is the number n lambda n: # We are iteratively removing elements one by one, so we use reduce reduce(( # same as the first if statement in our function # but written in different order because of reduce's syntax lambda all_nums, x: all_nums - set(range(x**2, n, x)) if (x in all_nums) # Reduce must return something on each iteration # Returning the unmodified set has the same effect as # ‘else: continue’ in the for loop else all_nums), # argument 2 of reduce (numbers to iterate over): nums_to_check range(2, int(n**0.5)), # argument 3 of reduce (starting set to modify): all_nums set(range(2, n)))
If you join all those lines together and replace all_nums
with r
, you get the original one-liner.
👉 Recommended Tutorial: The Sieve of Eratosthenes
A Note on Readability
One-liners are wonderful. They are powerful and, at times, elegant solutions to problems. However, they can be hard to read. And, as The Zen of Python states, ‘Readability counts.’
Although readability is not important for computers, it is important for humans. Code is meant to be read and understood by humans first and computers second.
Thus it’s better to write more lines of code that are easy to understand rather than a one-liner that takes hours to decipher.
That being said, the one-liners in this article will improve your coding skills. And it will make reading explicit, well-commented code a breeze. We hope you enjoyed working through them as much as we did creating them.
Where to Go From Here
If you had difficulties understanding some Python one-liners, you might want to improve your skills in writing Pythonic code.
But don’t worry. It’s not that hard if you have someone to guide you every step of the way. If you need someone like that, register for my free “Coffee Break Python” Email course where I give you Python micro lessons daily.
It’s the best way to improve on autopilot. My subscribers love it!