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

24 阅读2分钟

您正在编写一个库来帮助人们模拟种群,您可能有一个 Population 类,其中 t0 是 datetime 类型,initial 是种群的初始数量,growth 是种群的增长率。您希望为该类提供一个方法来确定给定时间点的种群数量,该时间点可以是 datetime 类型,也可以是包含自 t0 以来经过的秒数的浮点类型。此外,调用者还可以提供一个由 datetime 或者浮点类型时间组成的数组。

huake_00257_.jpg 2、解决方案

方法一:为每种类型编写一个单独的方法

您可以为每种类型编写一个单独的方法。例如,您可以编写一个 at_raw(t) 方法来处理 datetime 类型的时间,和一个 at_datetime(t) 方法来处理浮点类型的时间。

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

    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)

方法二:编写一个通用的方法

您也可以编写一个通用的 at(t) 方法来处理任何类型的时间。该方法将根据输入的时间类型自动进行转换。

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

    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)

方法三:使用鸭子类型

鸭子类型是一种设计模式,它允许您根据对象的属性和方法来使用对象,而无需关心对象的具体类型。在 Python 中,您可以使用鸭子类型来编写一个通用的 at(t) 方法,该方法可以处理任何类型的时间。

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

    def at(self, t):
        try:
            t = (t-self.t0).total_seconds()
        except AttributeError:
            pass
        try:
            t = [get_arr(t1)[0] for t1 in t]
        except TypeError:
            pass
        t = np.array(t)
        return self.initial*numpy.exp(self.growth*t)

哪种方法更好?

方法一和方法二都是可行的解决方案。方法一是针对每种类型的时间单独实现一个方法,而方法二则是使用一个通用的方法来处理所有类型的时间。方法一更加灵活,因为它允许您针对每种类型的时间进行优化,但方法二更加简洁,因为它只需要编写一个方法。

方法三使用鸭子类型来编写一个通用的 at(t) 方法,该方法可以处理任何类型的时间。这种方法非常简洁,但它可能不那么直观,因为它依赖于 Python 的鸭子类型。

最终,您应该选择哪种方法取决于您的具体需求。如果您需要针对每种类型的时间进行优化,那么您可以使用方法一。如果您更喜欢简洁的代码,那么您可以使用方法二或方法三。