Python’s Augmented Assignments 0

Everyone knows that in Python variables are just references and passing such reference to function effectively copies value of the reference to functions local scope, hence any assignment within function has no effect on original variable. Knowing that, this took me by surprise:


>>> def add_eggs(foo):
...     foo += ['eggs']
...
>>> spam = ['spam']
>>> add_eggs(spam)
>>> print spam
['spam', 'eggs']

This seemed to me as an error in Python interpreter, but after checking language reference I discovered it’s not; it’s intended behaviour (emphasis is mine):

An augmented assignment expression like x += 1 can be rewritten as x = x + 1 to achieve a similar, but not exactly equal effect. In the augmented version, x is only evaluated once. Also, when possible, the actual operation is performed in-place, meaning that rather than creating a new object and assigning that to the target, the old object is modified instead.

Quoted after: python docs

Equality is not always sufficient 0

I’ve just got hit by one of really typical errors while writing simple value type in Python. Consider following code:

class Simple(object):
    def __init__(self, val):
        self.val = val
    def __eq__(self, other):
        return self.val == other.val

The class Simple overrides equality operator delegating it to it’s value. Seems dead simple and easy for the first time. But not quite so. What will following snippet print?

a, b = Simple(3), Simple(3)
set_a, set_b = set([a]), set([b])
print 'a == b: ', a == b
print 'set_a == set_b', set_a == set_b

You’ve guessed it: True, False. This is because two sets may be equal only if all elements hashes are equal. So I thought I will fix it with this:

class Hashimple(object):
    def __init__(self, val):
        self.val = val
    def __eq__(self, other):
        return self.val == other.val
    def __hash__(self):
        return (self.val * 5) + 7

Seems better, but look at this snippet and guess once more:

a, b = Hashimple(3), Hashimple(3)
set_a, set_b = set([a]), set([b])
print 'Hashimple'
print 'a == b: ', a == b
print 'set_a == set_b', set_a == set_b
print 'a != b', a != b

True, True, True?!? Well, Python will not imply that a != b , not even when a == b.

This bug has been made thousands times by thousands of coders, it occurs not only in Python, but also in various other languages (Java, Ruby), it’s been described in lots of books, but I just keep forgetting about it. Maybe writing a blog post will help me remember?

Docs: __eq__, __hash__

Failed with Google App Engine 0

I’m writing a little app for my English course at Jagiellonian University in Django. Right now I’m hosting it here, on hauru.eu, but soon we’ll release a book we were producing whole year and thus I have to finish the app and make it public. I thought about putting it on Google App Engine  (think: free hosting in Python), but after two days of trying I must say I don’t see any point any more.

I wrote my app using many of convenience methods/classes provided by Django, but very few of them are supported by GAE. I’d have to rewrite half of code! No way. It’s right time to use some servers in KSI: Students’ Computer Science Club, which I’m proud member of.

I’m sure Google App Engine is powerful and convenient platform, but I don’t think Django fits there well. While reading about GAE I thought the best solution would be using some external libraries like Werkzeug, as GAE is based on WSGI interface.

Update (Dec 13, 2008): The little app is live and indeed running on KSIs server. Check it out, it’s called English++: English for Computer Science Students