Improve Your Python
3 Shortcuts for More Concise and Meaningful Python
My first book, Intuitive Python: Productive Development for Projects that Last, is now available from The Pragmatic Programmers. In fact, if you make it to the end of this article, you’ll get a promo code that will save you 35 percent on the ebook. With Intuitive Python, you hone your Python skills with a guided tour of the standard library and excellent third-party tools.
Many of my favorite Python patterns and idioms are in Intuitive Python, but not all of them. These three shortcuts will help you write more concise and meaningful Python. We’ll start off with a tip for manipulating files easily.
Shortcut 1
Use pathlib
to read files without using a with
context manager
You’ll often use a with
context manager when reading a file in Python to ensure that the underlying file is closed even if your program raises an unexpected exception. For example:
In the canonical example above, we opened example-file.txt
using with
context manager. f
is bound to a file object that you can use to interact with the file. In this case, we fetch the contents of example-file.txt
using the read
method. with open
returns a context manager that ensures the underlying file is closed either at the end of the with
block or after an unexpected exception is raised in the body of the with
statement.
The example works well, but it is a little verbose. The pathlib
module offers a number of conveniences for working with file system paths and files on your file system---I highly recommend it in general. One particular convenience offered by pathlib
is the pathlib.Path.read_text
method. pathlib.Path.read_text
lets you read the contents of a file without explicitly using a context manager:
In the above example, you instantiate a Path
object with the path you are interested in opening: example-file.txt
. Calling the read_text
method of the new Path
object returns the text contained in the underlying file. The value of contents
is the same as the value of contents
in the first example.
In case you are concerned about files being closed properly, note that Path.read_text
uses a with
context manager under the hood to ensure that the underlying file is closed appropriately. The with
context manager is still in play to ensure the file is closed for you, just abstracted away.
Path
also offers three related additional methods beyond read_text
. Namely: read_bytes
, write_text
, and write_bytes
. With these four methods, you can cover the majority of your file reading/writing needs without repeatedly writing with open(...)
context managers.
As you start working more withPath
objects, you’ll also find that Path
objects can augment and improve on functions you’re used to importing from the os
module.
With pathlib
added to your toolbelt, let’s look at another shortcut. Next, we’ll count iterations of a loop with the built-in function enumerate.
Shortcut 2
Get the current index in a for
loop using enumerate
It’s often useful to have a loop counter in a for
loop. To get the current index in a for
loop, you could initialize a counter variable and manually increment it. It's more concise, however, to use the Python built-in function enumerate
:
story
defines a string with three phrases all separated by newlines (\n
). Splitting on \n
creates a list with three entries: "What"
, "is"
, and "your favorite color?"
. This list is bound to the variable named lines
. Iterating over the lines
list with a for
loop successively yields all three parts of the story. Wrapping lines
in a call to enumerate
makes Python yield an additional element on every iteration of the for
loop. index
is bound to the return value from enumerate
(which is an increasing integer counter), and line
is an entry from the lines
list. The final result is that 0
is yielded with "What"
, 1
is yielded with "is"
, and 2
is yielded with "your favorite color?"
. You've just used enumerate
to generate line numbers for every line in a string.
enumerate
also supports a start
argument that allows you to modify which integer enumerate
begins counting at. For example, if you wanted to start your loop counter at 1
you could write the following:
The above example is identical to the previous one, except we’ve added start=1
as an argument to enumerate
. This change adjusts the final outputted counting sequence of line numbers from 0, 1, 2
to 1, 2, 3
.
Now you know how to save some time with enumerate
. Next up is a special class that allows your code to present a dictionary interface that doesn’t allow modifications.
Shortcut 3
Use MappingProxyType
to create a read-only dictionary
You can manipulate a normal Python dictionary several ways: add keys, remove keys, and update keys to point to new values. If you are passing around data that shouldn’t be modified, like configuration data, special user data, and so on, you’ll want to create a dictionary data structure that cannot have keys added, removed, or changed. That’s where MappingProxyType
comes in handy.
You can use MappingProxyType
to create a view on a dictionary that cannot be updated, like this:
In the above example, we instantiated a MappingProxyType
instance using a dictionary of user attributes. The returned MappingProxyType
instance is bound to a variable named user_details
. Trying to change the value of the "id"
key to 44
results in a TypeError
Exception
--- user_dict
doesn't allow keys to be added, removed, or replaced.
Similarly, if you tried to say user_details.pop("id")
or user_detail["new-key"] = "new-value"
you would also have gotten an Exception
forbidding the change. MappingProxyType
can be useful when you want to pass a mapping to code you might not necessarily trust---you can help guarantee that your input object won't be manipulated unexpectedly.
Python’s built-in frozenset
type may also be of interest to you. Similar to how MappingProxyType
creates a read-only view of a dictionary, you can use frozenset
to create a read-only view of a set
data structure.
You’ve just learned about three quick shortcuts that can improve your Python. If you’d like to dig into more Python, check out Intuitive Python. Through July 15th, you can use promo code intuitivepython35 on The Pragmatic Bookshelf website to save 35% on the ebook. Note that promo codes are not applicable to prior purchases.