Możesz po prostu użyć normalnej składni przekazywania argumentów w języku Python, aby określić tabelę crontab. Załóżmy na przykład, że definiujemy klasę Event jak poniżej:
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)
(Uwaga: Nie gruntownie przetestowane)
Następnie tablicę CronTab można określić w normalnej składni Pythona jako:
c = CronTab(
Event(perform_backup, 0, 2, dow=6 ),
Event(purge_temps, 0, range(9,18,2), dow=range(0,5))
)
W ten sposób zyskujesz pełną moc mechaniki argumentów Pythona (mieszanie argumentów pozycyjnych i słów kluczowych, i możesz używać nazw symbolicznych dla nazw tygodni i miesięcy)
Klasa CronTab zostałaby zdefiniowana jako po prostu spanie w przyrostach minutowych i wywoływanie check () dla każdego zdarzenia. (Prawdopodobnie są pewne subtelności z czasem letnim / strefami czasowymi, o których należy pamiętać). Oto szybka implementacja:
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)
Należy zwrócić uwagę na kilka rzeczy: dni tygodnia / miesiące Pythona są indeksowane przez zero (w przeciwieństwie do crona), a zakres ten wyklucza ostatni element, stąd składnia taka jak „1-5” staje się zakresem (0,5) - tj. [0,1,2, 3,4]. Jeśli wolisz składnię crona, parsowanie nie powinno być jednak zbyt trudne.