通常のPythonの引数渡し構文を使用して、crontabを指定できます。たとえば、次のようにEventクラスを定義するとします。
from datetime import datetime, timedelta
import time
# Some utility classes / functions first
class AllMatch(set):
"""Universal set - match everything"""
def __contains__(self, item): return True
allMatch = AllMatch()
def conv_to_set(obj): # Allow single integer to be provided
if isinstance(obj, (int,long)):
return set([obj]) # Single item
if not isinstance(obj, set):
obj = set(obj)
return obj
# The actual Event class
class Event(object):
def __init__(self, action, min=allMatch, hour=allMatch,
day=allMatch, month=allMatch, dow=allMatch,
args=(), kwargs={}):
self.mins = conv_to_set(min)
self.hours= conv_to_set(hour)
self.days = conv_to_set(day)
self.months = conv_to_set(month)
self.dow = conv_to_set(dow)
self.action = action
self.args = args
self.kwargs = kwargs
def matchtime(self, t):
"""Return True if this event should trigger at the specified datetime"""
return ((t.minute in self.mins) and
(t.hour in self.hours) and
(t.day in self.days) and
(t.month in self.months) and
(t.weekday() in self.dow))
def check(self, t):
if self.matchtime(t):
self.action(*self.args, **self.kwargs)
(注:完全にはテストされていません)
次に、CronTabを通常のPython構文で次のように指定できます。
c = CronTab(
Event(perform_backup, 0, 2, dow=6 ),
Event(purge_temps, 0, range(9,18,2), dow=range(0,5))
)
このようにして、Pythonの引数の仕組み(位置引数とキーワード引数を混合し、週と月の名前にシンボリック名を使用できます)を最大限に活用できます。
CronTabクラスは、単に分単位でスリープし、各イベントでcheck()を呼び出すように定義されます。(ただし、夏時間/タイムゾーンに注意が必要な微妙な点があります)。ここに簡単な実装があります:
class CronTab(object):
def __init__(self, *events):
self.events = events
def run(self):
t=datetime(*datetime.now().timetuple()[:5])
while 1:
for e in self.events:
e.check(t)
t += timedelta(minutes=1)
while datetime.now() < t:
time.sleep((t - datetime.now()).seconds)
注意すべきいくつかのこと:Pythonの平日/月は(cronとは異なり)ゼロインデックスであり、その範囲は最後の要素を除外します。したがって、「1-5」のような構文はrange(0,5)になります。つまり、[0,1,2、 3,4]。ただし、cron構文を使用する場合は、構文解析はそれほど難しくありません。