As a simple example, take a class
Ellipse that can return its properties such as area A
, circumference C
, major/minor axis a/b
, eccentricity e
etc. In order to get that, one obviously has to provide precisely two of its parameters to obtain all the other ones, though as a special case providing only one parameter should assume a circle. Three or more parameters that are consistent should yield a warning but work, otherwise obviously raise an exception.
So some examples of valid Ellipse
s are:
Ellipse(a=5, b=2)
Ellipse(A=3)
Ellipse(a=3, e=.1)
Ellipse(a=3, b=3, A=9*math.pi) # note the consistency
while invalid ones would be
Ellipse()
Ellipse(a=3, b=3, A=7)
The constructor would therefore either contain many =None
arguments,
class Ellipse(object):
def __init__(self, a=None, b=None, A=None, C=None, ...):
or, probably more sensible, a simple **kwargs
, maybe adding the option to provide a,b
as positional arguments,
class Ellipse(object):
def __init__(self, a=None, b=None, **kwargs):
kwargs.update({key: value
for key, value in (('a', a), ('b', b))
if value is not None})
So far, so good. But now comes the actual implementation, i.e. figuring out which parameters were provided and which were not and determine all the others depending on them, or check for consistency if required.
My first approach would be a simple yet tedious combination of many
if 'a' in kwargs:
a = kwargs['a']
if 'b' in kwargs:
b = kwargs['b']
A = kwargs['A'] = math.pi * a * b
f = kwargs['f'] = math.sqrt(a**2 - b**2)
...
elif 'f' in kwargs:
f = kwargs['f']
b = kwargs['b'] = math.sqrt(a**2 + f**2)
A = kwargs['A'] = math.pi * a * b
...
elif ...
and so on*. But is there no better way? Or is this class design totally bollocks and I should create constructors such as Ellipse.create_from_a_b(a, b)
, despite that basically making the "provide three or more consistent parameters" option impossible?
Bonus question: Since the ellipse's circumference involves elliptic integrals (or elliptic functions if the circumference is provided and the other parameters are to be obtained) which are not exactly computationally trivial, should those calculations actually be in the constructor or rather be put into the @property Ellipse.C
?
* I guess at least one readability improvement would be always extracting a
and b
and calculating the rest from them but that means recalculating the values already provided, wasting both time and precision...
This is known as an optional argument or optional parameter in Python. But if you have passed some value into the optional argument while calling the function, then the function will take that new value instead of the default value. DelftStack articles are written by software geeks like you.
In python, there is something called a default argument. It is also known as optional argument or optional parameter in Python. An argument or a parameter both mean the same thing. You can use these words interchangeably. An argument or a parameter is an input that a function takes.
This is unless we use optional arguments. In which case, we can specify fewer arguments than a function accepts because some arguments are optional. A Python optional argument is an argument with a default value. You can specify a default value for an argument using the assignment operator.
If two events are mutually exclusive, they are not independent. Also, independent events cannot be mutually exclusive. In probability theory, two events are mutually exclusive or disjoint if they do not occur at the same time. A clear case is the set of results of a single coin toss, which can end in either heads or tails, but not for both.
My proposal is focused on data encapsulation and code readability.
a) Pick pair on unambigous measurements to represent ellipse internally
class Ellipse(object):
def __init__(a, b):
self.a = a
self.b = b
b) Create family of properties to get desired metrics about ellipse
class Ellipse(object):
@property
def area(self):
return math.pi * self._x * self._b
c) Create factory class / factory methods with unambigous names:
class Ellipse(object):
@classmethod
def fromAreaAndCircumference(cls, area, circumference):
# convert area and circumference to common format
return cls(a, b)
Sample usage:
ellipse = Ellipse.fromLongAxisAndEccentricity(axis, eccentricity)
assert ellipse.a == axis
assert ellipse.eccentricity == eccentricity
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With