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...
The Home for People Who Like to Flip Out and Write Code
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...
Posted by Hank Gay at 19:22 View Comments
Labels: maven, sneak_attack, tuscany
Django Circular Model References highlights a neat trick to make Django models play nice with circular references.
Back to flipping out...
Posted by Hank Gay at 15:56 View Comments
Labels: django, python, sneak_attack
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...
Posted by Hank Gay at 05:41 View Comments
Labels: project_euler, python
Rosetta Code is a nifty site that has a set of common tasks implemented in many different languages.
Back to flipping out...
Posted by Hank Gay at 18:21 View Comments
Labels: sneak_attack
Short, easy-to-follow tutorial for Jersey, the Java RI for RESTful web services.
Back to flipping out...
Posted by Hank Gay at 13:09 View Comments
Labels: Java, REST, sneak_attack
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.
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.
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.
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...
Posted by Hank Gay at 14:46 View Comments
Labels: book_review, python
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.
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.
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".
*args
and **kw
Magic Arguments CarefullyThe 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.
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.
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.
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.
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.
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.
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...
Posted by Hank Gay at 13:37 View Comments
Labels: book_review, python
Quick! Who is this?
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.
Posted by Hank Gay at 08:46 View Comments
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...
Posted by Hank Gay at 13:05 View Comments
Labels: profiling, pycon, python, sneak_attack
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.
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.
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.
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.
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...
Posted by Hank Gay at 11:09 View Comments
Labels: five_things_I_hate, python
I'm sure you've all seen the Five Things meme. Here's the five things I hate about Java.
There's just enough generics-related type inferencing to leave me wanting more.
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.
I can't praise the REPL enough. Java should have had one of these in the JDK in 1.0.
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.
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.
This very nearly bumped Array Covariance. I really wish tail-call elimination would catch on in mainstream languages.
Back to flipping out...
Posted by Hank Gay at 10:35 View Comments
Labels: five_things_I_hate, Java