views:

88

answers:

3

I'm trying to create a class that will allow me to add/multiply/divide objects of the same class together or add/multiply numeric arguments to each member of the class

So my class is for coordinates (I am aware there are great packages out there that do everything I want better than I could ever hope to on my own, but now I'm just curious).

class GpsPoint(object):
    """A class for representing gps coordinates"""
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z
    def __add__(self, other):
        return GpsPoint(self.x + other.x, self.y + other.y, self.z + other.z)
    def __radd__(self, other):
        return GpsPoint(self.x + other, self.y + other, self.z + other)
    def __str__(self):
        return "%d, %d, %d" % (self.x, self.y, self.z)

This was my original attempt. I found it worked, but only if I used a numeric argument first

>>foo = GpsPoint(1,2,3)
>>print 5 + foo
6, 7, 8
>>print foo + 5
AttributeError: 'int' object has no attribute 'x'

So, what is the pythonic way to do this, is there a pythonic way, is this just silly? I see what the philosophical problem is with using isinstance() and I know I could toss in a try except block I'm just curious how I should go about this.

+1  A: 

You are going to have to try to determine what type other is, at least to the extent that it's compatible with GpsPoint. If you can't figure it out then just return NotImplemented and the interpreter will try to handle it from there.

Ignacio Vazquez-Abrams
A: 

Short answer: use isinstance().

There is no other way to dermine the type of "other" in your methods. Also, if you check the sources of many python libraries you will find that there are lots of places where isinstance() is used. So this is just the state of art in python:-).

pajton
+6  A: 

The "Pythonic" way is to "ask forgiveness rather than permission" - that is, instead of checking the type beforehand, try to add and, if it fails, catch the exception and deal with it, like so:

class GpsPoint(object):
    """A class for representing gps coordinates"""
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z
    def __add__(self, other):
        try:
            return GpsPoint(self.x + other.x, self.y + other.y, self.z + other.z)
        except AttributeError:
            return GpsPoint(self.x + other, self.y + other, self.z + other)
    def __radd__(self, other):
        try:
            return GpsPoint(self.x + other.x, self.y + other.y, self.z + other.z)
        except AttributeError:
            return GpsPoint(self.x + other, self.y + other, self.z + other)
    def __str__(self):
        return "%d, %d, %d" % (self.x, self.y, self.z)
Daniel G
Asking forgiveness is a good way to run into the false cognate problem, but in the case of overloaded numeric operators, it's pretty clear what x, y and z mean. You only have a problem if you, say, add an instance of a completely unrelated four-dimensional (w,x,y,z) number class: then you silently lose the w.
markpasc
Awesome, thanks. This is what I ended up doing (and `__radd__ = __add__`). I *feel* like it's slightly hacky but it suits my purposes fine, and appears to be well liked as an answer.
Tyler
What if your except block returned`self + GpsPoint(other, other, other)`That seems more the idea you have of mapping numbers to GpsPoints, that you want to change them to GpsPoints, then add them.
Tim Snowhite