6

如果,作为一个简化的例子,我正在编写一个库来帮助人们模拟人口,我可能有一个类,例如:

class Population:
    def __init__(self, t0, initial, growth):
        self.t0 = t0,
        self.initial = initial
        self.growth = growth

其中 t0 是日期时间类型。现在我想提供一种方法来确定给定时间的人口,无论是日期时间还是包含自 t0 以来的秒数的浮点数。此外,调用者提供这样的时间数组是合理的(如果是这样,我认为假设它们都属于同一类型是合理的)。我可以看到至少有两种方法可以做到这一点:

  1. 每种类型的方法

    def at_raw(self, t):
        if not isinstance(t, collections.Iterable):
            t = numpy.array([t])
        return self.initial*numpy.exp(self.growth*t)
    def at_datetime(self, t):
        if not isinstance(t, collections.Iterable):
            t = [t]
        dt = numpy.array([(t1-self.t0).total_seconds() for t1 in t])
        return self.at_raw(dt)
    
  2. 通用方法

    def at(self, t):
        if isinstance(t, datetime):
            t = (t-self.t0).total_seconds()
        if isinstance(t, collections.Iterable):
            if isinstance(t[0], datetime):
                t = [(t1-self.t0).total_seconds() for t1 in t]
        else:
            t = np.array([t])
        return self.initial*numpy.exp(self.growth*t)
    

两者都可以,但我不确定哪个更pythonic。我已经看到一些建议,类型检查表明糟糕的设计会建议方法 1,但由于这是一个供其他人使用的库,方法 2 可能会更有用。

请注意,有必要支持以浮点数形式给出的时间,即使只有库本身使用此功能,例如,我可能会实现一种方法,该方法在更复杂的模型中根查找固定点,其中浮点表示显然更可取。提前感谢您的任何建议或意见。

4

1 回答 1

5

我相信你可以在这里简单地坚持 Python 的 Duck Typing Philosophy

def at(self, t):
    def get_arr(t):
        try: # Iterate over me
            return [get_arr(t1)[0] for t1 in t]
        except TypeError:
            #Opps am not Iterable
            pass
        try: # you can subtract datetime object
            return [(t-self.t0).total_seconds()]
        except TypeError:
            #Opps am not a datetime object
            pass
        # I am just a float
        return [t]
    self.initial*numpy.exp(self.growth*np.array(get_arr(t)))

重要的是,您如何订购箱子

  1. 具体案例应先于一般案例。

    def foo(num):
        """Convert a string implementation to
           Python Object"""
        try: #First check if its an Integer
            return int(num)
        except ValueError:
            #Well not an Integer
            pass
        try: #Check if its a float
            return float(num)
        except ValueError:
            pass
        #Invalid Number
        raise TypeError("Invalid Number Specified")
    
  2. 默认案例应该是终止案例

  3. 如果连续案例相互排斥,则按可能性排序。
  4. 通过引发异常来为意外做好准备。毕竟Errors should never pass silently.
于 2013-10-14T17:56:52.547 回答