As a simple example, take a class
Ellipse that can return its properties such as area A
, circumference C
, major/minor axis a/b
a
from every pairing of the other parametersa
is the sameb
from every pairing of a
and another parametera
and b
Here's a shortened version with just a
, b
, e
, and f
that easily extends to other parameters:
class Ellipse():
def __init__(self, a=None, b=None, e=None, f=None):
if [a, b, e, f].count(None) > 2:
raise Exception('Not enough parameters to make an ellipse')
self.a, self.b, self.e, self.f = a, b, e, f
self.calculate_a()
for parameter in 'b', 'e', 'f': # Allows any multi-character parameter names
if self.__dict__[parameter] is None:
Ellipse.__dict__['calculate_' + parameter](self)
def calculate_a(self):
"""Calculate and compare a from every pair of other parameters
:raises Exception: if the ellipse parameters are inconsistent
"""
a_raw = 0 if self.a is None else self.a
a_be = 0 if not all((self.b, self.e)) else self.b / math.sqrt(1 - self.e**2)
a_bf = 0 if not all((self.b, self.f)) else math.sqrt(self.b**2 + self.f**2)
a_ef = 0 if not all((self.e, self.f)) else self.f / self.e
if len(set((a_raw, a_be, a_bf, a_ef)) - set((0,))) > 1:
raise Exception('Inconsistent parameters')
self.a = a_raw + a_be + a_bf + a_ef
def calculate_b(self):
"""Calculate and compare b from every pair of a and another parameter"""
b_ae = 0 if self.e is None else self.a * math.sqrt(1 - self.e**2)
b_af = 0 if self.f is None else math.sqrt(self.a**2 - self.f**2)
self.b = b_ae + b_af
def calculate_e(self):
"""Calculate e from a and b"""
self.e = math.sqrt(1 - (self.b / self.a)**2)
def calculate_f(self):
"""Calculate f from a and b"""
self.f = math.sqrt(self.a**2 - self.b**2)
It's pretty Pythonic, though the __dict__
usage might not be. The __dict__
way is fewer lines and less repetitive, but you can make it more explicit by breaking it out into separate if self.b is None: self.calculate_b()
lines.
I only coded e
and f
, but it's extensible. Just mimic e
and f
code with the equations for whatever you want to add (area, circumference, etc.) as a function of a
and b
.
I didn't include your request for one-parameter Ellipses to become circles, but that's just a check at the beginning of calculate_a
for whether there's only one parameter, in which case a
should be set to make the ellipse a circle (b
should be set if a
is the only one):
def calculate_a(self):
"""..."""
if [self.a, self.b, self.e, self.f].count(None) == 3:
if self.a is None:
# Set self.a to make a circle
else:
# Set self.b to make a circle
return
a_raw = ...