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)