Jack Le - 1 year ago 89
Python Question

# Best practice to implement multiple contructors in python

I'm pretty sure this has been asked many times but I'm still not sure how to implement the multiple constructors in Python. I know that in python, I can only have one constructor unlike in java or C# or C++. I'm still pretty new to it. Long story short, I need to implement a line object. The line will be represented by the function y = ax + b. So the only things I need to store in the line are a, b and a boolean for the special case where the line is vertical (a = infinity). In that case, a will store the x position of the line. To create a line, I have 3 ways. 1 is to directly put in a, b and the boolean. 2 is to put in 2 points in form of tuples. 3 is to put in a point and a vector. My code so far:

``````class line:
def __init__(self, a, b, noSlope):
self.a = a
self.b = b
self.noSlope = noSlope

def lineFromPoints(point1, point2):
deltaX = point2[0] - point1[0]
deltaY = point2[1] - point1[1]
if deltaX == 0:
return line(point1[0], 0, True)
else:
a = deltaY / deltaX
b = point1[1] - a * point1[0]
return line(a, b, False)

def lineFromVector(vector, point):
if vector[0] == 0:
return line(point1[0], 0, True)
else:
a = vector[1] / vector[0]
b = point1[1] - a * point1[0]
return line(a, b, False)
``````

Not sure if there's a better way to do this

UPDATE:

The more pythonic way of doing multiple constructors is with `@classmethod`, as suggested by Jim. Raymond Hettinger did a talk on Python's class development toolkit at Pycon 2013, where he talked about multiple constructors using `@classmethod`.

``````class Line:
def __init__(self, a, b, noSlope):
self.a = a
self.b = b
self.noSlope = noSlope

@classmethod
def fromPoints(cls, point1, point2):
deltaX = point2[0] - point1[0]
deltaY = point2[1] - point1[1]
if deltaX == 0:
return cls(point1[0], 0, True)
else:
a = deltaY / deltaX
b = point1[1] - a * point1[0]
return cls(a, b, False)

@classmethod
def fromVector(cls, vector, point):
if vector[0] == 0:
return cls(point1[0], 0, True)
else:
a = vector[1] / vector[0]
b = point1[1] - a * point1[0]
return cls(a, b, False)

line = Line.fromPoints((0,0), (1,1))
``````

Similar to `self`, the `cls` parameter for the `@classmethod` functions is implicitly passed as the calling class (in the example above, it would be `Line`). This is used to accommodate future subclasses using the additional constructors; it removes potential bugs from accidentally bypassing a subclass's implementation of a constructor by hard coding the base class in place of `cls`.

ORIGINAL POST:

If you want to enforce the use of your constructors, you can make them static methods, and have them return an instance of your class.

``````class line:
def __init__(self, a, b, noSlope):
self.a = a
self.b = b
self.noSlope = noSlope

@staticmethod
def lineFromPoints(point1, point2):
deltaX = point2[0] - point1[0]
deltaY = point2[1] - point1[1]
if deltaX == 0:
return line(point1[0], 0, True)
else:
a = deltaY / deltaX
b = point1[1] - a * point1[0]
return line(a, b, False)

@staticmethod
def lineFromVector(vector, point):
if vector[0] == 0:
return line(point1[0], 0, True)
else:
a = vector[1] / vector[0]
b = point1[1] - a * point1[0]
return line(a, b, False)

# Create instance of class
myLine = line.lineFromPoints((0,0), (1,1))
``````

EDIT:
If you want to force use of your constructors over the use of `Line.__init__`, you can use the following factory to hide direct instantiation of the Line class:

``````class LineFactory:
class Line:
def __init__(self, a, b, noSlope):
self.a = a
self.b = b
self.noSlope = noSlope

@staticmethod
def fromPoints(point1, point2):
deltaX = point2[0] - point1[0]
deltaY = point2[1] - point1[1]
if deltaX == 0:
return LineFactory.Line(point1[0], 0, True)
else:
a = deltaY / deltaX
b = point1[1] - a * point1[0]
return LineFactory.Line(a, b, False)

@staticmethod
def fromVector(vector, point):
if vector[0] == 0:
return LineFactory.Line(point1[0], 0, True)
else:
a = vector[1] / vector[0]
b = point1[1] - a * point1[0]
return LineFactory.Line(a, b, False)

# Create line
line = LineFactory.fromPoints((0,0), (1,1))
``````
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download