Skip to content

My first post (or create your own immutable objects!)

January 23, 2013

I’m an intermediate Python programmer who is trying to get better. As part of that, I’m going to start posting snippets of code to this blog and explain my thinking behind them. Any comments or suggestions would be greatly appreciated. Today’s project is a pretty trivial immutable quaternion class. For this post, I’m assuming a fairly high level of proficiency with Python, because I’m in a hurry an don’t have time to describe how to use Python’s magic __ methods very clearly. Hopefully, this blog will become more accessible as it goes.

In the Python course I’m teaching in my group, the question came up about how to create your own immutable object. Looking through the web, I found there were basically two solutions: use __slots__() and overwrite __getattr__() or extend the NamedTuple class from collections. Since I do not want to write a bunch of __ methods for basic things like equality and comparisons, I went with the namedtuple class. As its name implies, a named tuple is simply a tuple where you can access the data by indices, e.g. x[0], or by names, e.g. I really wanted to overwrite __getitem__() to get prevent accessing the data via indices, but that blew up the way NamedTuple accessed the named variables. Someday I will write out a full implementation that gives me exactly what I want. Finally, I was surprised I didn’t have to deal with __new__() when generating the object. The NamedTuple class won’t let you add new variables once the object is created, but it is completely cool with you manipulating its methods.

Now, on to the code. As I mentioned, the NamedTuple class lets you manipulate away on its methods, so I just let it handle the __new__() and __init__(). I created a NamedTuple with values s, i, j, and k for our quaternion values. Shockingly, Python isn’t cool with ‘1’ being a label, so I chose the letter s. You can also include a docstring with your NamedTuple, but I wanted to overwrite it with my class’s docstring, anyway. That leaves my two little magic methods to make the example not
nothing. First, I changed __str__() so that print x, where x is an instance of ImmutQuaternion, gives us something readable. Finally, __mult__() is the method that Python calls when you type x*y. I simply implemented the Hamiltonian product and returned the new immutable quaternion. One concern I would have actually implementing this is that there is no indication to the user that x*y != y*x. However, as they say, we’re all grown-ups here.

The code for today’s post is below. Or it can be found at my GitHub. In my next post, I’m going to create a (mutable) quaternion class and optimize it with Cython.

from collections import namedtuple

class ImmutQuaternion(namedtuple('ImmutQuaternion', ['s', 'i', 'j', 'k'])):
    This is the quaternion class that generates immutable quaternions 
    that you can multiply in the usual way (e.g. x*y returns a new 
    quaternion using the Hamiltonian product).
    def __mul__(self, q):
        if not isinstance(q, ImmutQuaternion):
            raise TypeError ("Product must be of two quaternions!")
        s = self.s*q.s - self.i*q.i - self.j*q.j - self.k*q.k
        i = self.s*q.i + self.i*q.s + self.j*q.k - self.k*q.j
        j = self.s*q.j - self.i*q.k + self.j*q.s + self.k*q.i
        k = self.s*q.k + self.i*q.j - self.j*q.i + self.k*q.s
        return ImmutQuaternion(s, i, j, k)
    def __str__(self):
        return '%f 1 %f i %f j %f k' % (self.s, self.i, self.j, self.k)

PS If anyone knows how to get the sourcecode to render at a nice standard 80 characters per line, I would greatly appreciate it.


From → Python tricks

Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: