6

簡単な例として、人々が集団をモデル化するのに役立つライブラリを作成している場合、次のようなクラスがあるとします。

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

ここで、t0 は datetime 型です。ここで、特定の時間の人口を決定するメソッドを提供したいと考えています。これは、日時または t0 からの秒数を含む浮動小数点数です。さらに、呼び出し元がそのような時間の配列を提供することは合理的です (そうであれば、それらはすべて同じ型であると想定するのが合理的だと思います)。これを達成するには、少なくとも 2 つの方法があります。

  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 がおそらくより有用です。

ライブラリ自体だけがこの機能を使用している場合でも、float として与えられた時間をサポートする必要があることに注意してください。提案やアドバイスをお寄せいただきありがとうございます。

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 に答える