Real Ultimate Programming

The Home for People Who Like to Flip Out and Write Code

Review of Expert Python Programming, Part Three

Chapter 4: Choosing Good Names

This chapter is aimed at helping improve API design, mostly by helping improve the names you choose when building the API. Ironically enough, not all of the advice is about naming, so the chapter title could be better. Most of the advice is good, although some of it overlaps with PEP 8 and some of it is far more general than just Python. That doesn’t dilute the value of the advice, but I will skip it in this review.

Best Practices for Arguments
Build Arguments by Iterative Design

This advice is applicable to pretty much any language, but it is surprising how many people get it wrong. Also, if you’re new to languages that allow you to specify default values for parameters, this section highlights one of the best uses for that feature.

Trust the Arguments and Your Tests

More solid advice: don’t try to recreate a static typing system in a dynamically typed language. This isn’t exactly profound insight, but a lot of people (myself included) make this mistake when they transition to dynamic typing from static typing. Instead of just saying “the tests will catch that”, which some interpret as “write unit tests and/or assertions to enforce static- style typing”, the author is careful to explain that the tests are supposed to test actual use cases. The author also mentions Design-by- Contract. While he doesn’t seem to favor it, he does provide a link to Contracts for Python. It should be noted that the related PEP 316 has been deferred, so some people may find the resulting code “unpythonic”.

Use *args and **kw Magic Arguments Carefully

The author acknowledges that use of *args and **kw (also seen as **kwargs) is sometimes necessary, e.g., metaprogramming, but in general considers them a design smell. He also offers advice for improving the design, e.g., accepting a single iterable parameter instead of *args.

Module and Package Names

Mostly mundane and duplicative of PEP 8, but there are a couple of gems: the convention of using a lib suffix in a module or package name if it is implementing a protocol, e.g., smtplib; using __init__ to import some APIs into the top level of the package, including a caveat about the increased potential of circular dependencies.

Working on APIs
Tracking Verbosity

Even though this is the sort of generic advice I said I was going to skip, I liked it so much I decided to include it anyway. If there is a common use case for some sequence of calls into your API, you should expose a function that encapsulates it. Doing anything else just invites errors.

Building the Namespace Tree

I really liked this section. In just a couple of short pages, the author shows an example of evolving the namespace structure for an application. I don’t have enough experience in the Python world to know if this is a realistic example, but I thought it was presented well and made good sense. I also like that the book addresses this topic at all. The Zen of Python says “Namespaces are one honking great idea—let’s do more of those!” but I don’t see many mentions of resources covering how to design them well.

Using Eggs

This sections provides a concise explanation of what eggs do and a sneak preview at how to define them. I would have liked more info, but the inset promises more details in Chapter 6.

Using a Deprecation Process

The advice in this section is also generic (don’t break an already-published API), but I mentioned it because it shows the Pythonic method for deprecating old APIs: DeprecationWarning.

Useful Tools

This section only lists two tools: Pylint and CloneDigger. They are useful, but some tips for using them to greatest effect would have been nice.

Back to flipping out…

Bravos, You’re Nothing to Me Now

Quick! Who is this?

A snake in the grass

That’s right, it’s the Atlanta Braves. Not satisfied with their classless treatment of John Smoltz, now the Braves have treated another future Hall-of-Famer shabbily by misleading Tom Glavine about his chances to make the big league club then releasing him to avoid paying him his roster bonus.

We now return you to your regularly (or not) scheduled programming blog updates.

Back to flipping out…

Five Things I Hate (or at Least Dislike) About Python

1. Implicit Variable Creation

This is probably my biggest complaint. Why would you want to implicitly create a variable the first time something is assigned to it? This might make sense in a language where variables are immutable by default (after all, you only ever assign a variable once), but Python isn’t. Also, I realize there is a technical difference between rebinding names and changing the value of a variable; I don’t find that particular distinction useful here.

2. Dearth of Collections (in the standard library)

Don’t get me wrong: defaultdict and namedtuple are nice, but on occasion I really find myself wishing for some more advanced data structures, e.g., Red-Black tree I’m not even talking about probabilistic structures like Bloom filters or skip lists.

3. Lack of Tail-call Elimination

I know it likely won’t happen but I still wish I had it. To me (and I’m sure many others), recursive algorithms are the most natural way to express certain algorithms, e.g., traversing a tree. I can do it using a loop, but it really drops me out of the zone.

4. Concurrency in the Standard Library

In an ideal world, Python would support concurrency on a level with first- class functions, similar to Erlang. It’s almost not even fair to ding Python on this, since pretty much every other language its age has the same problem, but a man can dream, right? At least the multiprocessing module made it into the standard library.

5. Interfaces

It would be really swell if Python had support for something like interfaces. I know that PEP 3119 introduced Abstract Base Classes, so this one is probably on the way to being remedied, but the feature is so new I haven’t yet encountered it in the wild.

Back to flipping out…

Five Things I Hate About Java

I’m sure you’ve all seen the Five Things meme. Here’s the five things I hate about Java.

1. Lack of Type Inferencing

There’s just enough generics-related type inferencing to leave me wanting more.

2. No First-class Functions

I don’t care if there are patterns for doing this, it’s not very idiomatic, and the boilerplate obscures the intent of the code, which largely defeats the purpose.

3. No Read-Eval-Print Loop (REPL)

I can’t praise the REPL enough. Java should have had one of these in the JDK in 1.0.

4. Checked Exceptions

The standard library is riddled with checked exceptions that really should have been unchecked, and third-party libraries have followed suit. In fact, Exception should have been unchecked and we should have CheckedException as a subclass instead of RuntimeException.

5. Array Covariance

It’s broken. Especially now that Java has covariant returns (thanks Java 5!), this bothers me just often enough that I’ve forgotten how broken it is right before I need/want it.

Honorable Mention: No Tail-call Elimination

This very nearly bumped Array Covariance. I really wish tail-call elimination would catch on in mainstream languages.

Back to flipping out…

Review of Expert Python Programming, Part Two

Chapter 3
Subclassing Built-in Types
  • I started learning Python after this was added, so it never occurred to me not to do this.
Accessing Methods from Superclasses
  • Tries to explain super, but it’s quite confusing (mostly due to the multiple-inheritance problems).
  • The standard docs do a better job of making it clear the main benefit is making maintenance easier in single-inheritance examples.

Understanding Python’s Method Resolution Order (MRO)

The section isn’t as clear as it could be, but it has solid information. It explains what the MRO is used for and how it’s different between 2.2 and 2.3, and the __mro__ attribute.

super Pitfalls

Points out some of the most common problems with super: mixing super and classic calls (and how to use __mro__ to choose what to do) and subclass constructors that take arguments that differ from their parent classes.

Best Practices
  • Solid, short (so you can remember it) section.
Descriptors and Properties

Descriptors

This section isn’t overly clear. It describes what descriptors are from a technical perspective, but doesn’t do a great job of explaining why you’d want to use them. Also, a fair number of the examples have errors, e.g., code for setting values when the text says it is for reading values. Luckily, it contains a link to the (more helpful) How-To Guide for Descriptors.

Properties

This section explains property and the property attributes it returns (though not necessarily why they’re so useful) and does a good job of pointing out some gotchas, e.g., the way they don’t pick up overridden methods. The solution offered is perfectly sensible: override the property instead of the (typically private) method bound to fget.

Slots
  • Short but informative section on slots which I haven’t seen mentioned before.
Meta-Programming

The __new__ Method

This section covers __new__ and its usefulness for making sure that a class’s invariants aren’t violated because a subclass didn’t explicitly invoke __init__.

The __metaclass__ method

This section covers customizing class creation using __metaclass__ and points out that, in most cases, there are easier-to-understand alternatives. One example of when there isn’t is adjusting read-only attributes, e.g., the __doc__ attribute of the built-in metaclass type. Other suggested usages for __metaclass__ include frameworks enforcing behavior across large groups of classes and orthogonal functionality such as logging. The section closes with a link to A Primer on Python Metaclass Programming.

Summary

The summary section is a short, bulleted list highlighting the most important points made in the chapter. Again, it’s short enough to be easily memorable.

Back to flipping out…