Expert Python Programming by Tarek Ziade Review by James Stockford
This book could as aptly be titled "Expert Python Development" with a subtitle along the lines of "Stakes in the Ground". The book's subtitle is "Best practices for designing, coding, and distributing your Python software." The stakes in the ground are the most widely accepted tools and techniques, with discussions backed up with references to related PEPs.
Here's a link to a Sample chapter: Download
Here's a link to the Packt's page.
The author, Tarek Ziade, has assembled techniques and wisdom that lets the diligent reader become a Python developer, from coding to building to testing to optimizing, all with preferred tools (Tarek's stakes in the ground) and plenty of code examples.
It seems that until now (late 2008), all books on Python introduce the Python language at the level of keywords and operators and essential data management. This book assumes all that. The reader should be an experienced programmer who knows at least the basics of the Python language and libraries and wants to improve coding skills as well as the skills needed to be an effective Python developer.
The book has a little over 350 pages, a ten-page index, and fourteen chapters. Chapter one begins with installation and tools, chapters two, three, and four present coding concerns, subsequent chapters show how to write packages and applications, manage software, document and test, and optimize. The final chapter reviews important design patterns. There is an open source bias. The content is solidly up to Python 2.5, touches on Python 2.6 at times, and hints at Python 2.7. Each chapter is divided into sub-sections and ends with a summary of most important points. The chapter sequence, each with its rigorous format, makes for a highly navigable book.
The balance of this review tries to bring to light a sense of the information and style that makes this book so distinctively valuable.
The first sentence in the first chapter begins "Python is good for developers." Along with installation instructions for Linux, Mac, and Windows, Chapter One has information about how to customize the interpreter's interactive prompt (PYTHONSTARTUP=~/.pythonstartup with example directives in the file) followed by sections for iPython, the improved interpreter, and for setuptools and EasyInstall, with instructions and advice. The chapter ends with a section on editors. Chapter One gives you a complete setup for an expert Python developer.
Chapters Two through Four present strategic rather than tactical issues of Python coding.
Chapter Two, titled Syntax Best Practices--Below the Class Level, treats list comprehensions, iterators and generators, coroutines, decorators, and the with keyword and contextlib. The discussion is in terms of techniques and patterns, not at all on the rudiments of the language. As an example, the Decorators section presents general techniques for writing a decorator and follows with four common patterns for decorators: argument checking, caching, proxy, and context provider.
There are URLs that point to the python.org documentation, including PEPs, and other internet sources of pertinent information.
The accompanying code examples are progressively elegant.
Some quotes include "Pythonic syntax is a syntax that uses the most efficient idioms...." "[For every loop]..., try to replace it with a list comprehension." Consider generators "every time you deal with a function that returns a sequence or works in a loop." "Generators can also help in breaking the complexity and raising the efficiency of some data transformation algorithms...." "A decorator should focus on arguments that the wrapped function or method receives and returns, and...limit its introspection work as much as possible." My personal favorite is "Keep the code simple, not the data...."
Chapter Three, titled Syntax Best Practices--Above the Class Level, treats subclassing the built-ins and sub-classing in general, with a great discussion of Method Resolution Order as it affects multiple inheritance and a Best Practices sub-section that includes the recommendation that "multiple inheritance should be avoided".
The chapter discusses descriptors and properties in light of Python's lack of the "private" keyword found in C++ and Java, an introspection and a meta descriptor, and a good warning discussion about Python's idiosyncratic approach to not using methods overridden in derived classes.
There is a rare, if brief, discussion of using the __slots__ attribute to sidestep the creation of a class __dict__ list.
The chapter ends with a section on meta-programming with the __new__ and the __metaclass__ methods. "__new__ is the answer to the need for implicit initialization of object states...[you can]...define an initialization at a lower lefel than __init__, which is always called."
Chapter Four, titled Choosing Good Names, opens by refering to PEP 8 and follows with recommendations for variables, functions and methods, arguments, classes, and more. It is a complement to PEP 8 that adds not only some practical wisdom but advice regarding API considerations such as the namespace tree, splitting code, and using eggs. The chapter ends with a discussion of tools such as PyLint and CloneDigger.
Chapter Five, Writing a Package, Chapter Six, Writing an Application, and Chapter Seven, Working with zc.buildout, focus on the tools for creating egg-based packages for distribution.
Chapter Five assumes that you're designing an eggs-based project using distutils and setuptools to organize, release, and distribute your software in a namespaced package directory tree. It introduces the setup.py script and then progressively exercises the commands to build modules, libraries, C extensions, and scripts to create a binary tree that can be installed and uninstalled in Python's site-packages/ directory.
Additional tools let you hook in Nose for testing and integrate your package with PyPi (or your choice of some other Python application server). The chapter ends with an extensive look at using Python Paste to create and use a package template.
Chapter Six revisits the process to flesh out an application, using Tarek's Atomisator application as fodder.http://tarekziade.wordpress.com/2008/08/20/atomisator-a-framework-to-build-custom-rss-feeds/
He discusses how to use the easy_install tool to set up the environment and add Nose as a test runner, then how to divide out the package structure with a notable discussion of "leaky wrappers" (per the Facade pattern) vis a vis full wrappers for API considerations.
The package testing involves doctest, mock objects, and for the database portion of the app using SQLAlchemy to manage object-relational mappings. The result is a package structure that is "ready to be distributed by pushing eggs to PyPI."
Chapter Seven uses the zc.buildout tool to put together a more complex application that, when installed, can span directories, locating log files in /var/log/ and configuration files in /etc/ and so on. Packages are egg-based. There is extensive exercise of the buildout tool's recipe feature, which automates the build process.
Chapter Eight, Managing Code, Chapter Nine, Managing Life Cycle, and Chapter Ten, Documenting Your Project, have to do with software project maintenance.
After discussion, he advises you pick a distributed rather than a centralized version control system. Mercurial is Tarek's pick. He discusses setting it up and integrating it with Apache and buildbot for automating testing through releases.
Trac is his choice for a life cycle management tool, and discussion bears on installation and subsequent integration with Apache.
The Documenting chapter, which focuses on design docs, presents a set of common sense rule that, like playing the blues, is conceptually easy but requires constant practice to do well.
Chapter Eleven, Test-Driven Development, Chapter Twelve, Optimization: General Principles and Profiling Techniques, Chapter Thirteen, Optimization: Solutions, and Chapter Fourteen, Useful Design Patterns, add icing to the development cake.
As with his other chapters, the test chapter begins with general discussion, in this case with some emphasis on regression and how to contain it. The tools include unittest, doctest, Nose, and py.test. The chapter ends with discussion of fake behavior and mock objects and finally document-driven development.
The first optimization chapter begins with common-sense reminders first to make code work and keep it readable then address issues of scale and speed followed by an extensive section on profiling.
The second optimization chapter begins with reducing complexity and measuring cyclomatic complexity as well as Big-O notation, followed by an investigation of optimizing list searches (with a suggestion to consider sets, as members are accessed through a hash rather than walking indexes, which lowers the big-O factor), and more. The threading section is likewise extensive, including discussion of GIL limitations on multiprocessing and the use of pyprocessing for forking, where that is an acceptable approach. The chapter ends with discussion of caching (use the memcached tool).
The patterns chapter covers creational patterns (the Singleton), structural patterns (the Adapter, the java-style Interface, the Proxy, and the Facade), and behavioral patterns (the Observer, the Visitor, and the Template), with Python code examples and discussions.
When I proudly showed my copy of Expert Python Programming to my friend Daniel, he gasped with admiring respect and said "I bought this book," which I think is the ultimate recommendation.