recursive method in __init__

Robert Brewer fumanchu at amor.org
Wed Nov 3 18:17:59 EST 2004


paul koelle wrote:
> I thought it would be nice to have instances that can "live" 
> somehow in 
> the "background" and do some tasks without being told so. The 
> problem in 
> the code below is: calling new_host = Host(ip, mac, collector) never 
> "returns" because the the self.update() method gets called 
> recursively. 
> Im pretty sure I have to restructure the code and call the update() 
> method from outside but I ask out of curiosity and to get 
> some ideas how 
> to do such things elegantly.

Use threading. Try three cooperating functions:

1. run(), which does the work you want done,
2. motivate(), which starts a new thread, which starts by calling...
3. _cycle(), which calls motivate(), then run().

The example below is from Cation, a web application framework. You start
the cycle via:
>>> worker = ApplicationWorker(name, app, recurrence, **kwargs)
>>> worker.motivate()


class ApplicationWorker(object):
    """Perform work for an application on a schedule.
    
    You must override work(), which is called at each interval.
    
    active: a boolean flag indicating whether or not the Worker's run()
        method should be executed at each interval. Notice that, even if
        active is False, recurring Workers will continue to schedule new
        threads--they simply won't do anything at run() time.
    
    kwargs: a dictionary where each k, v pair represents an (optional)
        kwarg to the worker. "key" should be a string, the name of the
        argument. Values should be populated with defaults where
possible.
        Override this at the class level when subclassing
ApplicationWorker.
    """
    
    kwargs = {}
    
    def __init__(self, name, application, recurrence, **kwargs):
        self.name = name
        self.application = application
        self.log = application.logger
        self.recurrence = recurrence
        if self.recurrence:
            # Throw away the first occurrence value,
            # which is almost always .now()
            self.recurrence.next()
        self.kwargs = {}
        self.kwargs.update(self.__class__.kwargs)
        self.kwargs.update(kwargs)
        self.createdate = datetime.datetime.now()
        self.lastrun = None
        self.active = True
    
    def motivate(self):
        """Start a new immediate or recurring thread for work."""
        if self.recurrence:
            # Start a recurring, timed Thread.
            nextThread = threading.Timer(self.recurrence.interval(),
                                         self._cycle)
            nextThread.start()
        else:
            # Start a single, non-recurring thread.
            threading.Thread(None, self.run).start()
    
    def _cycle(self):
        """Run the worker on a schedule."""
        self.motivate()
        self.run()
    
    def run(self):
        """Prepare for work. Errors are logged, then ignored."""
        if self.active:
            try:
                self.work()
                self.lastrun = datetime.datetime.now()
                msg = (u"Worker '%s' completed successfully." %
self.name)
                self.log.info(msg)
            except Exception:
                self.log.exception(self.__class__.__name__)
    
    def work(self):
        raise NotImplementedError


Robert Brewer
MIS
Amor Ministries
fumanchu at amor.org



More information about the Python-list mailing list