Constructor overloading

Peter Otten __peter__ at
Wed Jun 9 13:42:08 CEST 2004

Sergey Krushinsky wrote:

> Hello all,
> Is there a common way to emulate constructor overloading in Python class?
> For instanse, I have 3 classes:
> 1/ Polar - to hold polar coordinates;
> 2/ Cartesian - to hold cartesian coordinates;
> 3/ Coordinates3D, which holds synchronized instances of the both in
> __p__ and __c__ fields respectively.
> I want to design Coordinates3D so that when instantiated with Polar
> argument, self.__p__=argument passed to constructor, and self.__c__ is
> calculated. When argument is Cartesian, self.__c__=argument, and
> self.__p__ is calculated. Runtime type checking works, but maybe there
> is a better way?
> Thanks in advance,
> Sergey

Given that Polar and Cartesian could easily grow the missing attributes via
properties, Coordiantes3D seems to be mainly a speed hack and should not
influence the design too much. One approach would be to make a unified
Point class that takes keyword arguments for x, y, z, r, phi, theta and
calculates the missing parameters either immediately in __init__() or
lazily on attribute access (I use 2D examples througout):

class LazyPoint(object):
    def getX(self):
            return self._x
        except AttributeError:
            self._x = self.r * math.cos(self.phi)
            return self._x
    x = property(getX) 

Another option would be to add calculated attributes, e. g. x, y, z to
Polar, (without caching) and construct the CachingPoint aka Coordinates3D
using these:

class Point(object):
    """ Shared implementation for Polar, Cartesion, and CachingPoint """
    r = property(lambda self: self._r)
    phi = property(lambda self: self._phi)
    x = property(lambda self: self._x)
    y = property(lambda self: self._y)
    def __str__(self):
        return "r=%s, phi=%s, x=%s, y=%s" % \
            (self.r, self.phi, self.x, self.y)

class Polar(Point):
    def __init__(self, r, phi):
        self._r = r
        self._phi = phi
    x = property(lambda self: self.r * math.cos(self.phi))
    y = property(lambda self: self.r * math.sin(self.phi))

class Cartesian(Point):
    def __init__(self, x, y):
        self._x = x
        self._y = y
    r = property(lambda self: math.sqrt(self.x*self.x+self.y*self.y))
    phi = property(lambda self: math.atan2(self.y, self.x))

class CachingPoint(Point):
    def __init__(self, point):
        # as both Polar and Cartesion support the full
        # attribute set, no type checking is needed here
        self._x = point.x
        self._y = point.y
        self._r = point.r
        self._phi = point.phi

if __name__ == "__main__":
    p = Polar(1.0, math.pi/4.0)
    print p
    print CachingPoint(p)
    print "---"
    p = Cartesian(3.0, 4.0)
    print p
    print CachingPoint(p)

More information about the Python-list mailing list