中野智文のブログ

データ・マエショリストのメモ

luigi で パラメータで与えられた日付をtimedelta を使って増減させたい

背景

luigi にて、パラメータで与えられた日付に対して、固定日分前(例えば一週間など)を求めたい。

from datetime import timedelta
import luigi


class MyTask(luigi.Task):
    date = luigi.DateParameter()
    start_date = date - timedelta(days=7)

と書くと、次のようなエラー。

unsupported operand type(s) for -: 'DateParameter' and 'datetime.timedelta'

確かに、date はDateParameterなので、エラーの通りなのだが。

stackoverflow.com

での、回答者のコメントでは、 “DateParameter returns a value that is a python date. ” といってるので、半分信じてしまった。 ちなみにこのQAは役立たない。なぜならデフォルト値の計算をしたいわけではないから。

クラス変数とインスタンス変数の違い

関数の中の、self.date はクラス変数と思っていたが、間違いだ。これはインスタンス変数だ。

厄介なことに、 self.date の表記は python 的にはクラス変数でもインスタンス変数にもなるらしい。 インスタンス変数として「初期化」すれば、クラス変数は隠蔽され以後インスタンス変数として扱われる。 ただ参照するだけならば、クラス変数として扱われる。

d.hatena.ne.jp

結局、self.dateインスタンス変数ということは、親のクラスのインスタンス初期化の処理などで、クラス変数の設定通りの動作が行われ、self.date というインスタンス変数に値がセットされたのだろう。

解決

from datetime import timedelta
import luigi


class MyTask(luigi.Task):
    date = luigi.DateParameter()

    def requires(self):
        start_date = self.date - timedelta(days=7)    

もし、固定の日でなく、パラメータで与えたいのであれば、TimeDeltaParameter を使おう。

http://luigi.readthedocs.io/en/stable/api/luigi.parameter.html#luigi.parameter.TimeDeltaParameter