Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple constructors in python

How to combine the following 2 classes into one class, Rectangle, so that a Rectangle object can be created either by rect = Rectangle(side_a, side_b) or rect = Rectangle(side_a, area)?

class Rectangle1:
    def __init__(self, side_a, side_b):
        self.side_a = side_a
        self.side_b = side_b
        self.area = self.side_a * self.side_b

class Rectangle2:
    def __init__(self, side_a, area):
        self.side_a = side_a
        self.area = area
        self.side_b = self.area / side_a
like image 444
zhuhuren Avatar asked Mar 15 '17 20:03

zhuhuren


2 Answers

As demonstrated here.

class Rectangle:

    def __init__(self, a, b):
        """ Create a new rectangle with sides of length a and b.
        """
        self.side_a = side_a
        self.side_b = side_b
        self.area = self.side_a * self.side_b

    @classmethod
    def from_sides(cls, a, b):
        return cls(a, b)

    @classmethod
    def from_area(cls, a, o):
        return cls(a, o/a)

You can then create rectangles as

r1 = Rectangle.from_sides(s1, s2)
r2 = Rectangle.from_area(s1, a)
like image 168
PidgeyUsedGust Avatar answered Oct 15 '22 12:10

PidgeyUsedGust


You cannot overload methods with methods of the same name. Well, you can, but only the last one is then visible.

The other option is keyword-only arguments.

With Python 3, you could write:

class Rectangle:
    def __init__(self, side_a, *, side_b=None, area=None):
        self.side_a = side_a
        if side_b is None and area is None:
            raise Exception("Provide either side_b or area")
        if side_b is not None and area is not None:
            raise Exception("Provide either side_b or area, not both")
        if side_b is not None:
            self.side_b = side_b
            self.area = self.side_a * self.side_b
        else:
            self.area = area
            self.side_b = self.area / side_a

using * in the middle forces the user to use keyword argument passing from that point, not allowing positionnal, which prevents the mistakes. And the (rather clumsy) manual checking for None logic ensures that one and only one keyword parameter is passed to the constructor. The inside is complex, but the interface is safe to use, that's the main point here.

r = Rectangle(10,area=20)
r2 = Rectangle(10,side_b=20)
r3 = Rectangle(10,20)   # doesn't run, need keyword arguments
like image 20
Jean-François Fabre Avatar answered Oct 15 '22 12:10

Jean-François Fabre