How to pythonically have partially-mutually exclusive optional arguments?

后端 未结 7 2235
鱼传尺愫
鱼传尺愫 2021-02-13 18:04

As a simple example, take a class Ellipse that can return its properties such as area A, circumference C, major/minor axis a/b

相关标签:
7条回答
  • 2021-02-13 19:09

    I would check for the consistency of the data each time you set a parameter.

    import math
    tol = 1e-9
    class Ellipse(object):
        def __init__(self, a=None, b=None, A=None, a_b=None):
            self.a = self.b = self.A = self.a_b = None 
            self.set_short_axis(a)
            self.set_long_axis(b)
            self.set_area(A)
            self.set_maj_min_axis(a_b)
    
        def set_short_axis(self, a):
            self.a = a
            self.check()
    
        def set_long_axis(self, b):
            self.b = b
            self.check()
    
        def set_maj_min_axis(self, a_b):
            self.a_b = a_b
            self.check()
    
        def set_area(self, A):
            self.A = A
            self.check()
    
        def check(self):
            if self.a and self.b and self.A:
                if not math.fabs(self.A - self.a * self.b * math.pi) <= tol:
                    raise Exception('A=a*b*pi does not check!')
            if self.a and self.b and self.a_b:
                if not math.fabs(self.a / float(self.b) - self.a_b) <= tol:
                    raise Exception('a_b=a/b does not check!')
    

    The main:

    e1 = Ellipse(a=3, b=3, a_b=1)
    e2 = Ellipse(a=3, b=3, A=27)
    

    The first ellipse object is consistent; set_maj_min_axis(1) passes fine.

    The second is not; set_area(27) fails, at least within the 1e-9 tolerance specified, and raises an error.

    Edit 1

    Some additional lines are needed for the cases when the uses supply a, a_b and A, in the check() method:

        if self.a and self.A and self.a_b:
            if not math.fabs(self.A - self.a **2 / self.a_b * math.pi) <= tol:
                raise Exception('A=a*a/a_b*pi does not check!')
        if self.b and self.A and self.a_b:
            if not math.fabs(self.A - self.b **2 * self.a_b * math.pi) <= tol:
                raise Exception('A=b*b*a_b*pi does not check!')
    

    Main:

    e3 = Ellipse(b=3.0, a_b=1.0, A=27) 
    

    An arguably wiser way would be to calculate self.b = self.a / float(self.a_b) directly into the set method of a_b. Since you decide yourself of the order of the set methods in the constructor, that might be more manageable than to write dozens of checks.

    0 讨论(0)
提交回复
热议问题