В качестве простого примера возьмите class
Ellipse, который может вернуть свои свойства, такие как площадь A
, окружность C
, основная/вспомогательная ось a/b
, эксцентриситет e
и т.д. Чтобы получить это, очевидно, что нужно предоставить ровно два из его параметров, чтобы получить все остальные, хотя в качестве специального случая, предусматривающего только один параметр, должен быть принят круг. Три или более согласованных параметра должны давать предупреждение, но работать, иначе явно возникает исключение.
Итак, некоторые примеры действительных Ellipse
:
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
в то время как недопустимыми будут
Ellipse()
Ellipse(a=3, b=3, A=7)
Таким образом, конструктор будет содержать либо много аргументов =None
,
class Ellipse(object):
def __init__(self, a=None, b=None, A=None, C=None, ...):
или, возможно, более разумный, простой **kwargs
, возможно, добавив опцию для предоставления a,b
в качестве позиционных аргументов,
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})
До сих пор так хорошо. Но теперь идет фактическая реализация, то есть выяснение, какие параметры были предоставлены, а какие нет и определить все остальные в зависимости от них, или проверить согласованность, если требуется.
Мой первый подход был бы простой, но утомительной комбинацией многих
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 ...
и т.д. *. Но нет ли лучшего способа? Или этот класс полностью блокируется, и я должен создавать конструкторы, такие как Ellipse.create_from_a_b(a, b)
, несмотря на то, что в принципе невозможна опция "предоставить три или более согласованных параметров"?
Бонусный вопрос: поскольку окружность эллипса включает в себя эллиптические интегралы (или эллиптические функции, если окружность предоставлена, а остальные параметры должны быть получены) которые не являются точно вычислительно тривиальными, должны ли эти вычисления фактически находиться в конструкторе или, скорее, быть помещены в @property Ellipse.C
?
* Я предполагаю, что хотя бы одно улучшение читаемости будет всегда извлекать A
и b
и вычислять остальную часть из них, но это означает пересчет уже предоставленных значений, теряя время и точность...