functors

Jack Diederich jack at performancedrivers.com
Wed Jul 2 03:22:17 EDT 2003


On Tue, Jul 01, 2003 at 06:25:18PM -0700, Tom Plunket wrote:
> How can I create a functor object in Python?
> 
> What I want (being a C++ coder <g>), is to be able to create an
> object that I is callable.  The following is my attempt, but it
> doesn't work:

I would make countdown dumber, and make the call more explicit

def countdown(thismany)
  for (i) in range(thismany):
    yield False
  yield True
  while True:
    yield False

>     def Update(self):
>         while not self.done:
>             self.countdown.Update()
becomes

def Update(self):
  while not self.done:
    if (self.countdown.next()):
      self.Callback() # person reading the code knows what happens

but if you really want the hidden callback, just change the countdown()

def countdown(thismany, call_this):
  for (i) in range(thismany):
    yield 69 # ignored by caller anyway
  call_this() # make the callback
  while True:
    yield 42 # more ignored yields   

But I'm not sure if this is what you really want, the countdown() keeps going
even after it has fired.  Hence the 'While True: yield False'

If you need the callback because you have a whole bunch and can't keep track
of each one individually, I'd make a parent class that decrements everyone
and pops people after they fire.

class Watcher(object):
  def __init__(self):
    self.watched = []
    self.i = 0

  def watch(count, call_this):
    self.watched.append((self.i+count, call_this))
  
  def decrement(self):
    self.i += 1
    callthese = filter(lambda x:x[0]<i, self.watched)
    self.watched = filter(lambda x:x[0]>=i, self.watched)

    for (dummy, callthis) in callthese:
      callthis()

Just for fun, let's play with itertools

from itertools import *

def countdown(thismany):
  return chain(repeat(False, thismany), [True], repeat(False))

or the abusive

def countdown(thismany, callthis):
  def fakeout(): # because "lambda x:yield x()" isn't legal
    yield callthis()
  return chain(repeat(None, thismany-1), fakeout(), repeat(None))

and the totally abusive (and totally untested)

class Watcher(object):
  def __init__(self):
    self.watched = repeat(None)
    self.curr = 0
  def watch(self, count, callthis):
    def fakeout():
      yield callthis()
    assert(count > self.curr) # new job must fire after the current longest one
    self.watched = chain(repeat(None, count-1-self.curr), fakeout(), self.watched)
    self.curr = count
  def decrement(self):
    if (self.curr):
      self.curr -= 1
    self.watched.next()
 

Enjoy,

-jackdied





More information about the Python-list mailing list