8 Coolest Python Programming Language Features
After writing nearly 20 articles just about Python, I’ve decided to take some time to reflect on what I’ve learned. For instance, I recently wrote a compilation article which includes 70+ Python code snippets. Now, I’ve put together a list of some of the coolest Python programming language features.
Coolest Python Features List
And without further ado, let’s take a look at some of the coolest Python features. If you think I’ve missed any, feel free to drop them in the comments.
List Comprehensions
By far, my favorite feature in Python is the list comprehension. Honestly, the feature isn’t all that interesting; it’s just a convenient way to generate lists. That said, it’s a feature that I haven’t seen in any other popular language (e.g. Java, C, C++, etc.). As a result, I make sure to take advantage of it as often as possible. Here are a few examples:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 | # Generates a list containing values from 0 to 9 [i for i in range( 10 )] # Generates a list of all even values from 0 to 9 [i for i range( 10 ) if i % 2 == 0 ] # Generates a list containing values from 1 to 10 [i + 1 for i in range( 10 )] # Generates a list containing values from 0 to - 9 [-i for i in range( 10 )] # Generates all possible pairs between 0 and 9 [(a, b) for a in range( 10 ) for b in range( 10 )] # Shallow copies another list my_list = [ 1 , 3 , 5 , 7 , 9 ] [item for item in my_list] |
Since a list comprehension creates a list, we’re able to work with the output like any other list:
1 2 3 4 | # Generates a list containing values from 0 to 9 nums = [i for i in range( 10 )] nums[ 0 ] # returns 0 nums[ 1 ] # returns 1 |
If you’re interested in learning how to write these yourself, I have an article just for you. In it, you’ll learn more about the syntax as well as a few application areas. If you have any of your own examples, feel free to share them in the comments.
Generator Expressions
One of the nice things about learning the list comprehension syntax is that it allows you to also write generator expressions. After all, they’re very similar—one just saves you space. That’s right! Generator expressions don’t actually create lists. Instead, they provide the means for generating one item at a time of a list without ever constructing that list. Take a look:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 | # Generates values from 0 to 9 (i for i in range( 10 )]) # Generates values from 0 to 9 (i for i range( 10 ) if i % 2 == 0 ) # Generates values from 1 to 10 (i + 1 for i in range( 10 )]) # Generates values from 0 to - 9 (-i for i in range( 10 )) # Generates all possible pairs between 0 and 9 ((a, b) for a in range( 10 ) for b in range( 10 )) # Generates a shallow copy of another list my_list = [ 1 , 3 , 5 , 7 , 9 ] (item for item in my_list) |
Notice how similar the syntax is to the list comprehension. However, the application is slightly different. Instead of indexing the elements, we have to use a special function:
1 2 3 4 | # Generates values from 0 to 9 nums = (i for i in range( 10 )]) next(num) # returns 0 next(num) # returns 1 |
Since a generator is an iterable, we can also get away with using the for loop syntax:
1 2 3 4 | # Generates values from 0 to 9 nums = (i for i in range( 10 )]) for num in nums: print(num) # prints each item in the generator |
Once we’ve exhausted every element, the generator expression becomes useless. In other words, we can only generate every element once. After that, we have to write the expression again.
Slice Assignment
Have you ever wanted to replace entire sections of a list? Well, Python has a feature that allows you to do just that in a single line: slice assignment. Like slicing, slice assignment allows you to specify a region of a list. Of course, the difference is that slice assignment then lets you replace that region with whatever you want:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 | my_list = [ 1 , 2 , 3 ] # Appending a list with slice assignment my_list[len(my_list):] = [ 4 ] # Prepending a list with slice assignment my_list[: 0 ] = [ 0 ] # Replacing middle element midpoint = len(my_list) // 2 my_list[midpoint: midpoint + 1 ] = [- 2 ] # Replacing arbitrary subsection my_list[: 2 ] = [ 3 , 4 , 5 ] |
As I’ve mentioned in a related article, slice assignment doesn’t stop there. We can use any iterable on the right side. For example, we could use strings, tuples, list comprehensions, or even generator expressions. In other words, our previous two features can make an appearance:
1 2 | my_list = [ 1 , 2 , 3 ] my_list[len(my_list):] = (item for item in range( 5 )) |
Since learning about slice assignment in late 2019, I’ve been obsessed with it. As a result, I think it’s my second favorite feature right behind list comprehensions. Right now, I don’t have an article covering this feature in more detail, so you’re welcome to share some of your favorite examples in the comments.
Iterable Unpacking (aka Destructuring)
If you’ve checked out my article on getting the last item of a list, you might recall that iterable unpacking was one of the solutions. The idea being that we can split a list into two pieces: the last item and everything else:
1 2 | my_list = [ 1 , 2 , 3 ] *remainder, last_item = my_list |
Well, iterable unpacking can do more than retrieve the end of a list. For example, it can be used to swap variables:
1 2 3 | a = 1 b = 2 b, a = a, b |
Normally, we’d need three lines of code to perform a swap: one to create a temporary variable, another to overwrite one of the variables, and the last to copy the temporary variable to the other variable. With iterable unpacking, it’s a single line of code.
If iterable unpacking looks familiar to you, you might know it from its other name: destructuring. Oddly enough, I featured destructuring in an article covering some of my favorite features of any programming language.
That said, I don’t use iterable unpacking very often. If you have any good examples that would supplement this list, feel free to share them.
Negative Indexing
Of all the features on this list, negative indexing is perhaps the most subtle. After all, many modern programming languages have some form of list indexing. However, few have a way of getting the last element of a list so elegantly:
1 2 | my_list = [ 1 , 2 , 3 ] last_item = my_list[- 1 ] |
In addition to being able to access list elements in reverse, we can also use negative indexing with list methods like insert()
, pop()
, and index()
:
1 2 3 4 | my_list = [ 'h' , 'e' , 'l' , 'l' , 'o' ] my_list.insert(- 1 , 'l' ) # [ 'h' , 'e' , 'l' , 'l' , 'l' , 'o' ] my_list.pop(- 2 ) # [ 'h' , 'e' , 'l' , 'l' , 'o' ] my_list.index( 'l' , - 2 ) # 3 |
If you like negative indexing, you’ll be happy to know this feature doesn’t stop with lists. Feel free to use it with strings, tuples, and other sequences.
Dictionary Comprehensions
Previously in this list, I mentioned list comprehensions. Apparently, that feature is so good that the developers decided to expand its capabilities to encompass other data structures like dictionaries. After all, wouldn’t it be nice to be able to generate a dictionary in a single line of code? Well, as of PEP 274, you can:
1 2 3 4 5 6 7 | # Generates a dictionary of numbers to letters {num: chr( 65 + num) for num in range( 5 )} # Generates the same thing nums = [ 1 , 2 , 3 , 4 , 5 ] letters = [ "A" , "B" , "C" , "D" , "E" ] {num: letter for num, letter in zip(nums, letters)} |
Typically, I use a dictionary comprehension to merge two lists into a dictionary. That said, I’m sure there are other use cases. Feel free to share some of your favorite it in the comments.
Chaining Comparisons
In many modern programming languages, comparing values is a simple process. For example, in Java, I can compare two numbers as follows:
1 | 17 > 5 |
In this example, the result is a boolean, true
. As a result, the following expression is illegal in Java:
1 | 17 > 5 > 1 |
Here, 17 > 5
evaluates to true. Then, the expression true > 1
is evaluated. Since this is nonsensical, the compiler crashes.
In Python, however, we can chain comparisons without any risks. In other words, the same expression above is perfectly valid, and it returns True
.
Under the hood, each comparison is computed just like Java. However, each intermediate result is ANDed with the result of the other comparison. For example, 17 > 5
returns True
. Then, 5 > 1
returns True. Finally, the results are combined by and
which returns True
.
Personally, I haven’t used this feature much, but it’s gotten a lot of attention on the development end. For example, PEP 535 mentions a few updates to the chaining protocol. If you know of any cool use cases for this feature, let me know in the comments.
f-Strings
Finally, we come to one of my favorite “new” (PEP 498) Python features, f-Strings. Normally, when we create strings for debugging, we lazily print them with concatenation. If we’re clever, we might use some of the string formatting techniques. Now, we can get the best of both worlds with f-Strings:
1 2 3 | age = 25 name = 'Jeremy' print(f 'My name is {name}, and I am {age}' ) |
In this example, we’ve created a string from two variables: name
and age
. All we had to do was prepend our string with an f
. Then, we can place any expression we want in braces, and it will be interpreted. For example, age
is a number which is automatically converted to its string representation.
I really love this f-String syntax because it solves a lot of common string formatting issues. For example, it makes string formatting very easy to read (unlike concatenation). Likewise, it makes it obvious what the output string will look like (again, unlike concatenation). Finally, there’s no issues with positioning of variables (unlike string interpolation). What you see is what you get.
While f-Strings are really helpful, I don’t find myself using them beyond debugging. Do you have any examples you’d like to share?
Honorable Mentions
As someone who really loves working with Python, I had a hard time keeping this list short. As a result, here are a few additional features that didn’t make the cut:
- For/Else loops
- Imaginary numbers
- Any() and All()
- Returning multiple values (tuples)
- Arbitrarily large integers
- Keyword arguments
- Sets
- Joining strings
- Multiplying strings
- Walrus operator
- String interpolation
- Slicing
Of course, with how enormous the standard library is in Python, I’m sure there are even more clever bits of syntax. In addition, Python development is very active, so I wouldn’t be surprised to see even more features in the future. Perhaps I’ll update this list from time to time as new features appear.
Recommendations
With all that said, thanks for sticking around to check out this list. Over the next couple months, I’ll be focusing more on Python and Git content, so expect to see more articles like this in the future. If there’s anything you’d like to see, drop a note in the comments or feel free to contact me directly.
In the meantime, support this website by hopping on the mailing list, becoming a patron, or exploring the shop. Otherwise, keep browsing the following related articles:
- The Coolest Programming Language Features
- How to Convert Two Lists to a Dictionary in Python
- How to Format a String in Python
Finally, you might get some value out of the following Python resources from Amazon (ad):
- Python: 4 Books in 1: Ultimate Beginner’s Guide, 7 Days Crash Course, Advanced Guide, and Data Science, Learn Computer Programming and Machine Learning with Step-by-Step Exercises
- Python Pocket Reference: Python In Your Pocket
Otherwise, thanks again for your time. I appreciate it!
Published on Web Code Geeks with permission by Jeremy Grifski, partner at our WCG program. See the original article here: 8 Coolest Python Programming Language Features Opinions expressed by Web Code Geeks contributors are their own. |