Effective Python

Book cover image

For a long time, there was a big gap in the intermediate to advanced Python book space. There was Tarek Ziade’s Expert Python Programming, a really good book that started aging as Python moved on. There were books on individual topics such as network programming or web development, but these were limited in scope and could not be recommended to people looking to advance their general knowledge of the language. Fortunately, this situation has now drastically improved, thanks to a number of new publications, among which this one can be counted. Others are Fluent Python and the Python Cookbook.

Effective Python consists of 59 concrete recipes for writing, well, effective code. The recipes are very varied, and range from the simplest things like looping and slicing, to more complex topics such as class metaprogramming. Every tip is discussed in depth with all relevant aspects, and there is ample sample code. The recipes are organized roughly around different topics such as Metaclasses and Attributes, Classes and Inheritance, Concurrency and Parallelism etc. The Python target is 3, as all code samples adhere to its syntax, but any differences to Python 2 are explicitly stated and discussed. Some recipes go more towards patterns: e.g. “Register class existence with metaclasses” explains how to use the metaclass feature to create a class registry by only subclassing. These chapters are really useful as they give concrete examples of how abstract features can be used to accomplish sophisticated functionality. Others remind the programmer to prefer certain features of the language in preference to others (e.g. when dealing with circular imports), whereas others deal with what could be called “community” aspects of Python prgoramming, as in how to write packages that are good citizens of the Python world of programming.

Despite having already read sample code, blog posts or book chapters on most of the topics, I was surprised by how useful some examples are, and the detail in which they are discussed. One example is the descriptor chapter, which explains a rarely used feature of the language. The chapter is nicely bookended by discussions of the property decorator and the special methods for attribute access, giving the user a very good overview of the various ways of controlling attribute access. Another really well-written chapter is the one on how to use queues to coordinate between threads. This chapter nicely explains how to properly use the Queue class, by first giving an example of how a job queue can be built inefficiently, and then explaining a much more efficient and elegant counter-example.

The Queue chapter is a part of the Concurrency and Parallelism topic. This topic, despite the really nicely executed treatment of threads, unfortunately ends up being the weakest part of the book, due to the very simple reason that there was so much change in Python in this area. The new asyncio package is not discussed at all, and the coroutines that are at the heart of this package are explained at a very low level, without a clear sense of why they would be useful for concurrency and asynchronous IO.

As I mentioned in the beginning, this book is a very valuable contribution to the Python bookshelf, and is highly recommended to developers of all levels who want to refresh and cement their knowledge of this wonderful language.