Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I implement polymorphic arithmetic operators pythonicly?

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.

like image 753
Tyler Avatar asked Feb 27 '23 11:02

Tyler


2 Answers

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)
like image 124
Daniel G Avatar answered Apr 26 '23 23:04

Daniel G


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.

like image 28
Ignacio Vazquez-Abrams Avatar answered Apr 27 '23 01:04

Ignacio Vazquez-Abrams