如何pythonically有部分互斥的可选参数? [英] How to pythonically have partially-mutually exclusive optional arguments?

查看:21
本文介绍了如何pythonically有部分互斥的可选参数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

举一个简单的例子,以一个 class Ellipse 为例,它可以返回其属性,例如面积A、周长C、长/短轴a/b、偏心率e等.为了得到这个,显然必须提供精确的两个参数才能获得所有其他参数,但作为一种特殊情况,只提供一个参数应该假设一个圆.三个或更多一致的参数应该产生警告但有效,否则显然会引发异常.

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 eetc. 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.

所以一些有效的 Ellipse 示例是:

So some examples of valid Ellipses 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

而无效的则是

Ellipse()
Ellipse(a=3, b=3, A=7)

因此构造函数要么包含许多 =None 参数,

The constructor would therefore either contain many =None arguments,

class Ellipse(object):
    def __init__(self, a=None, b=None, A=None, C=None, ...):

或者,可能更明智,一个简单的 **kwargs,也许添加选项以提供 a,b 作为位置参数,

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 ...

依此类推*.但是就没有更好的办法了吗?或者这个类设计完全是胡扯,我应该创建诸如 Ellipse.create_from_a_b(a, b) 这样的构造函数,尽管这基本上使得提供三个或更多一致的参数"选项变得不可能?

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?

额外问题:由于椭圆的周长涉及椭圆积分(或椭圆函数,如果提供了周长并且要获得其他参数)这在计算上并不完全是微不足道的,这些计算是否应该在构造函数中或者更确切地说是放在 @property Ellipse.C 中?

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?

* 我想至少有一个可读性改进总是提取 ab 并从中计算其余部分,但这意味着重新计算已经提供的值,既浪费时间又浪费精度...

* 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...

推荐答案

我的提案侧重于 数据封装和代码可读性.

My proposal is focused on data encapsulation and code readability.

a) 在明确的测量值上选择对以在内部表示椭圆

a) Pick pair on unambigous measurements to represent ellipse internally

class Ellipse(object):
    def __init__(a, b):
        self.a = a
        self.b = 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) 创建具有明确名称的工厂类/工厂方法:

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)

示例用法:

ellipse = Ellipse.fromLongAxisAndEccentricity(axis, eccentricity)
assert ellipse.a == axis
assert ellipse.eccentricity == eccentricity

这篇关于如何pythonically有部分互斥的可选参数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆