Pythonic编写接受多种类型的库函数的方法?

时间:2013-10-14 17:14:44

标签: python

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

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

其中t0的类型为datetime。现在我想提供一种方法来确定给定时间的总体,无论是日期时间还是包含自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)
    
  3. 要么工作,但我不确定哪个更pythonic。我已经看到一些建议,类型检查表明设计方法1的设计不好,但由于这是一个供其他人使用的库,方法2可能会更有用。

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

1 个答案:

答案 0 :(得分: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.