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