Python

The Power of Portlets

I've been an advocate, user and sometimes promoter of the Plone CMS (an extensible content management system built on the Zope application server, using the Python scripting language) for quite some time. For me, Plone's most important feature is the ability to create Plone "products", which plug into the CMS. This allows the creation of a web portal that provides standard HTML CMS functions out-of-the-box, but can be extended to include almost any imaginable application. There's also a great versioning system built into Plone products that allows a CMS administrator to update a product right from the user interface. It also doesn't hurt that I chose Python as my main scripting language (sorry Ruby users/lovers/zealots, but Ruby was my dogs name ... I didn't want to get the two confused. Just kidding! I like Python's consistent and minimalistic syntax. Unlike PERL, there's generally only one right way to do it).

With many sites already running on Plone, I still haven't been able to justify using it for any major web application development projects. For these, we need industrial strength scalability, a more structured language and the support of a mature application server. Combined with the availability of a large pool of expert developers, Java and J2EE has always made the most sense. The problem with selecting Java for these projects was the lack of a framework that allowed the easy, modular development of the application. The adoption of JSR-168 Portlets by the Java community and its implementation by several major application server vendors has finally created an environment that promotes modular components on a Java driven web application.

Strings are a Domain-Specific Language

Question: Isn't a domain-specific language just the same thing as a library? (Source: Pretty much everyone the first time they hear of DSLs.)

Answer: No, a DSL is much more than a library, and I have an example that won't make you say, "Well, sure, if you're doing something that esoteric..."

Lambda at Work

Lambda
Finally, several years after learning lambda expressions, I got a chance to use one at work a few days ago. As long as I'm putting a notch in my nerd belt, I'd like to write about what lambda is and how it can be useful.

A lambda expression defines an anonymous function. Here's a regular function definition:

def inc(x):
    return x + 1

This definition binds the name inc in the local namespace to a function object. To get the exact same functionality using lambda, assign the lambda expression to a variable:

inc = lambda x: x + 1

A lambda has two parts: the argument list (only one arg in this case) before the: and an expression after. It can't contain statements (like assignments or print) because it's an expression itself. This is a pretty useless example, so let me show how I used it today.

Python Flyweights

I mentioned at the end of my post on Python Equality that another way to solve the example given was to use the flyweight pattern. I gave code for playing cards that would end up with many small duplicate objects in memory, and that memory usage can be reduced if (as in the example) the objects don't have extra state that wasn't used for testing equality.

Let's look at the final version of the Card class and its usage again:

values = ('2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A')
suits = ('h', 'c', 'd', 's')
 
class Card:
    def __init__(self, value, suit):
        self.value, self.suit = value, suit

    def __repr__(self):
        return "<Card: %s%s>" % (self.value, self.card)

    def __eq__(self, card):
        return self.value == card.value and self.suit == card.suit

    def __ne__(self, card):
       return not self.__eq__(card)

>>> c1 = Card('J', 'h')
>>> c2 = Card('J', 'h')
>>> c1 == c2
True
>>> id(c1), id(c2)
(-1210559028, -1210558804)

As designed in the previous blog post, two different objects (as seen by their different ids) equate because of the custom __eq__() handler.

But this is a bit silly -- Cards are so small and simple, having identical objects is wasteful. If we're writing the code for a casino, we don't really want several thousand Jacks of Hearts, we want many references to one object. The idea is that instantiating a Card object checks a hidden pool of objects for a duplicate and returns it, creating a new object only if needed. (Code based on that of Duncan Booth.)

import weakref

class Card(object):
    _CardPool = weakref.WeakValueDictionary()

    def __new__(cls, value, suit):
        obj = Card._CardPool.get(value + suit, None)
        if not obj:
            obj = object.__new__(cls)
            Card._CardPool[value + suit] = obj
            obj.value, obj.suit = value, suit

        return obj

Notice that this uses new-style classes. (Side note: I cringe at anything named "new", "next", "updated", etc. because they tell me nothing. If the only thing you can say about a reimplementation is that it's not the old one, put down your copy of Refactoring and back away from the computer. Take up writing toothpaste advertisements.) If you're wondering what's up with __new__, Guido explains the difference best:

__new__ is the first step in instance construction, invoked before __init__. The __new__ method is called with the class as its first argument; its responsibility is to return a new instance of that class. Compare this to __init__: __init__ is called with an instance as its first argument, and it doesn't return anything; its responsibility is to initialize the instance.

The other possibly-unfamiliar element is the WeakValueDictionary. In a nutshell, it's a dictionary that deletes its entries if no other variables point to them. When instantiating a Card object, it checks in the Card class's _CardPool to return an existing object, or creates a new Card object if needed.

If you're confused, take a few minutes to play with the code. Insert print statements into __new__ to show you the contents of _CardPool.items() and whether a new object is created. There's a lot of important object orientation concepts at work in a short block of code: inheritance, the difference between classes and objects, references, and overriding.

I've removed the __eq__ and __ne__ calls because two Cards with the same value and suit are the same objects, saving our casino many gigs of precious RAM:

Equality for Python


A few days ago in #chipy, the chat room for the Chicago Python Users Group, we had a chat about how Python determines equality. It's a pretty neat and extensible technique, so I'm going to walk through how I recently used it for playing cards.

Here's the basic Card class. Note that I'm going to totally skip things like error-checking and documentation to keep the example obvious.

values = ('2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A')
suits = ('h', 'c', 'd', 's')

class Card:
    def __init__(self, value, suit):
        self.value, self.suit = value, suit

    def __repr__(self):
        return "<Card: %s%s>" % (self.value, self.card)

Man, does code get short when you don't bother checking for errors. The usage is pretty clear, but there's one odd issue:

Versioning - The Next Big Thing

In the web development world, anyways. So, in the grand scheme of things, maybe not a huge deal to anyone else. Versioning is going to be one of the biggest problems and opportunities there is in web development, and it's going to take us at least five years to get it right.

Actually, let me admit up front that five years is a shot in the dark, and optimistic to boot. If people keep hanging out with bondage and discipline languages like Java and C# that are still catching up to language and framework developments from the 90's it'll take us more like ten years. (Attention Lisp Weenies: Yes, I know you solved every problem forty years ago for certain values of "solved" and "problem" while the rest of us were getting work done.) Not only is versioning a difficult technical problem, it will be difficult to educate programmers in what it is, how it works, and why you'll wish you used about a year after you decided it was too much work.

New Contributor - Peter Harkins

Let's all give a warm welcome to our newest contributor, the incredibly brilliant and good-looking Peter Harkins.

That's right, clap for me -- er, him, clap for him. I'm not writing this about myself. I mean he's not. Crap.

Hi, folks. I'm a new contributor to CodeSnipers. I'll be writing mostly about design and coding, though I may wander into MicroISV territory if any of my side projects should start doing particularly well.

To tell you a little about myself, I'm a 25-year old web developer in Chicago, IL, USA, Earth. I've been programming for about fourteen years, professionally for the last 5.5. My constant obsession is writing code that's just a little bit better, a little bit smarter, a little bit higher-level. Even though the steps I've taken and will be writing about are small, they're a great way to improve code and design every time you touch it.

Indexing Experiment - Queries With Parentheses

As indicated in Indexing Experiment - Expressing Queries, I want to allow for more interesting queries with this week's post. Using last week's sample data, I'd like to form expressions, such as

  • Python and PHP
  • Python or PHP
  • (Python not PHP) or Javascript
  • ((Python not PHP) and Buildbot) or Javascript
  • Python and (PHP and AJAX)

In short, last week's example will be expanded to allow usage of parentheses.

Indexing Experiment - Expressing Queries

In last week's post, I started this indexing experiment by creating a simple index based on the words found at specified URLs. Today, I want to look at querying such an index. Using last week's example, my goal is to find all indexed documents containing the words

  • Python and PHP
  • Python or PHP
  • Python not PHP

And so forth. Let's take a look.

Indexing Experiment

Not that the discussion of web crawling is over - far from it - but I thought it would be nice to start tinkering with indexing a little bit. This post will bring a very simple example of creating such an index then. The example is intentionally simple to show how easy it is to get started on writing an indexing scheme in Python.