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):

try:

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)