2009-06-24

Sneak Attack: Maven Archetypes for Apache Tuscany

The Tuscany community has put together a wiki that, among other things, describes some Maven archetypes for getting started with Tuscany. Trust me, this is a real win.

Back to flipping out...

Sneak Attack: Django Circular Model References

Django Circular Model References highlights a neat trick to make Django models play nice with circular references.

Back to flipping out...

2009-06-15

Project Euler: Problem 11, Redux

I've already solved Problem 11, but I didn't really do a great job. As BlueRaja pointed out in a comment, I was doing twice as much work as I needed to. Since I was revisiting this code anyway, I decided to play around a little bit with zip and itertools. Here's the new and improved solution:


"""Solve Problem 11 from Project Euler."""
import itertools
import operator


OFFSET = 3
GRID = [
    [8, 2, 22, 97, 38, 15, 0, 40, 0, 75, 4, 5, 7, 78, 52, 12, 50, 77, 91, 8],
    [49, 49, 99, 40, 17, 81, 18, 57, 60, 87, 17, 40, 98, 43, 69, 48, 4, 56, 62, 0],
    [81, 49, 31, 73, 55, 79, 14, 29, 93, 71, 40, 67, 53, 88, 30, 3, 49, 13, 36, 65],
    [52, 70, 95, 23, 4, 60, 11, 42, 69, 24, 68, 56, 1, 32, 56, 71, 37, 2, 36, 91],
    [22, 31, 16, 71, 51, 67, 63, 89, 41, 92, 36, 54, 22, 40, 40, 28, 66, 33, 13, 80],
    [24, 47, 32, 60, 99, 3, 45, 2, 44, 75, 33, 53, 78, 36, 84, 20, 35, 17, 12, 50],
    [32, 98, 81, 28, 64, 23, 67, 10, 26, 38, 40, 67, 59, 54, 70, 66, 18, 38, 64, 70],
    [67, 26, 20, 68, 2, 62, 12, 20, 95, 63, 94, 39, 63, 8, 40, 91, 66, 49, 94, 21],
    [24, 55, 58, 5, 66, 73, 99, 26, 97, 17, 78, 78, 96, 83, 14, 88, 34, 89, 63, 72],
    [21, 36, 23, 9, 75, 0, 76, 44, 20, 45, 35, 14, 0, 61, 33, 97, 34, 31, 33, 95],
    [78, 17, 53, 28, 22, 75, 31, 67, 15, 94, 3, 80, 4, 62, 16, 14, 9, 53, 56, 92],
    [16, 39, 5, 42, 96, 35, 31, 47, 55, 58, 88, 24, 0, 17, 54, 24, 36, 29, 85, 57],
    [86, 56, 0, 48, 35, 71, 89, 7, 5, 44, 44, 37, 44, 60, 21, 58, 51, 54, 17, 58],
    [19, 80, 81, 68, 5, 94, 47, 69, 28, 73, 92, 13, 86, 52, 17, 77, 4, 89, 55, 40],
    [4, 52, 8, 83, 97, 35, 99, 16, 7, 97, 57, 32, 16, 26, 26, 79, 33, 27, 98, 66],
    [88, 36, 68, 87, 57, 62, 20, 72, 3, 46, 33, 67, 46, 55, 12, 32, 63, 93, 53, 69],
    [4, 42, 16, 73, 38, 25, 39, 11, 24, 94, 72, 18, 8, 46, 29, 32, 40, 62, 76, 36],
    [20, 69, 36, 41, 72, 30, 23, 88, 34, 62, 99, 69, 82, 67, 59, 85, 74, 4, 36, 16],
    [20, 73, 35, 29, 78, 31, 90, 1, 74, 31, 49, 71, 48, 86, 81, 16, 23, 57, 5, 54],
    [1, 70, 54, 71, 83, 51, 54, 69, 16, 92, 33, 48, 61, 43, 52, 1, 89, 19, 67, 48]
]
INVALID_COORDS_PRODUCT = 0


def _calc_down(row_index, col_index):
    """Calculate the product of the sequence going straight down from ``row_index``."""
    cols = itertools.repeat(col_index, OFFSET + 1)
    last_row = min(row_index + OFFSET + 1, len(GRID))
    coords = zip(xrange(row_index, last_row), cols)
    values = (GRID[row][col] for row, col in coords)
    return reduce(operator.mul, values)


def _calc_right(row_index, col_index):
    """Calculate the product of the sequence going straight right from ``col_index``."""
    rows = itertools.repeat(row_index, OFFSET + 1)
    last_col = min(col_index + OFFSET + 1, len(GRID[row_index]))
    coords = zip(rows, xrange(col_index, last_col))
    values = (GRID[row][col] for row, col in coords)
    return reduce(operator.mul, values)


def _calc_up_right(row_index, col_index):
    """Calculate the product of the sequence going up and to the right from (``row_index``, ``col_index``)."""
    last_row = max(row_index - OFFSET - 1, -1)
    last_col = min(col_index + OFFSET + 1, len(GRID[row_index]))
    coords = zip(xrange(row_index, last_row, -1), xrange(col_index, last_col))
    values = (GRID[row][col] for row, col in coords)
    return reduce(operator.mul, values)


def _calc_down_right(row_index, col_index):
    """Calculate the product of the sequence going down and to the right from (``row_index``, ``col_index``)."""
    last_row = min(row_index + OFFSET + 1, len(GRID))
    last_col = min(col_index + OFFSET + 1, len(GRID[row_index]))
    coords = zip(xrange(row_index, last_row), xrange(col_index, last_col))
    values = (GRID[row][col] for row, col in coords)
    return reduce(operator.mul, values)


def _get_max_product_for_coordinate(row, col):
    """Find the maximum product achievable from (``row``, ``col``)."""
    return max(_calc_up_right(row, col), _calc_right(row, col), _calc_down_right(row, col), _calc_down(row, col))


def problem_11():
    """Find the largest product of four adjacent elements."""
    products = set()
    for row in range(len(GRID)):
        for col in range(len(GRID[row])):
            products.add(_get_max_product_for_coordinate(row, col))
    return max(products)


if __name__ == '__main__':
    print problem_11()

Back to flipping out...

2009-06-13

Sneak Attack: Rosetta Code

Rosetta Code is a nifty site that has a set of common tasks implemented in many different languages.

Back to flipping out...

2009-06-06

Review of Expert Python Programming, Part Four

Chapter 5: Writing a Package

A Common Pattern for All Packages

This section provides all the details necessary to create a namespaced package that consists of multiple eggs glued together by a master egg using distutils and setuptools. There are multiple subsections that cover everything you should need to build your project, register it with the Cheeseshop (or any other package index), and upload it for the world to enjoy.

How to Uninstall a Package

This section provides a short rationalization for why there isn't a built-in uninstall command and the current workaround. It's not mentioned in the book, but the author is currently working on improving distutils, and an uninstall command is on the agenda. The full details are in the Adding an Uninstall Function section of PEP 376.

The Template-Based Approach

After covering the basics of building and distributing a package in the previous section, this section focuses on using templates to reduce the tedium in creating consistent application skeletons. The tool used in this section is Python Paste. There are a couple of short examples using pre-existing templates.

Creating the Package Template

This section covers the process of creating a custom template that describes the structure introduce in the first section.

The rest of the chapter just covers generic aspects of the development cycle, such as version numbering, so I will skip it for this review.

Back to flipping out...

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...

2009-06-05

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.

2009-06-01

Sneak Attack: Introduction to Python Profiling (PyCon talk)

This PyCon talk on profiling is really good stuff. Also, it's nice that he points to KCachegrind and RunSnakeRun for better visualizations than the default from cProfile.

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...