accumulators

  • Thread starter Eugene Van den Bulke
  • Start date
E

Eugene Van den Bulke

Hi,

I have just finished reading Paul Graham Hackers & Painters book (which
I recommend even though he seems a bit hard on Python)

In chapter 13 of his book he wants to demonstrate LISP power VS other
languages (to be precise he wants to illustrate what he means by
relative power of programming language).

"We want to write a function that generates accumulators - a function
that takes a number n, and returns a function that takes another number
i and returns n incremented by i (that's incremented by, not plus. An
accumulator has to accumulate).

In Common Lisp this would be:
(defun foo (n)
(lambda (i) (incf n i)))

....

Python doesn't fully support lexical variables, you have to create a
data structure to hold the value of n. And although Python does have a
function data type, there is no literal representation for one (unless
the body is only a single expression) so you need to create a named
function to return. This is what you end up with:

def foo(n):
s=[n]
def bar(i):
s[0]+=i
return s[0]
return bar
"

It seems to me that this code does the job (but I am not sure I
understand exactly what an accumulator is):

def test(n):
return lambda i: n+i

Is that an accumulator? If it is, PG must have written this chapter
working on an older verion of Python ...

Regards,

Eugene Van den Bulke
 
P

Paul Rubin

Eugene Van den Bulke said:
It seems to me that this code does the job (but I am not sure I
understand exactly what an accumulator is):

def test(n):
return lambda i: n+i

Is that an accumulator? If it is, PG must have written this chapter
working on an older verion of Python ...

No. The idea of an accumulator is that whenever you call it, the
internal state updates. That is, if accum(n) creates an accumulator,
you should be able to say:

a = accum(3) # create accumulator holding 3
print accum(2) # prints "5"
print accum(3) # prints "8"
print accum(1) # prints "9"

etc. The Pythonic way to do it is with a class instance:

class accum:
def __init__(self, n):
self.s = n
def __call__(self, i):
self.s += i
return self.s

a = accum(3)
(etc.)

however, for programmers comfortable with the Lisp idioms of using
internal lambdas, the class/object approach is cumbersome.
 
P

Peter Otten

Paul said:
a = accum(3) # create accumulator holding 3
print accum(2) # prints "5"
print accum(3) # prints "8"
print accum(1) # prints "9"

Should be

a = accum(3) # create accumulator holding 3
print a(2) # prints "5"
print a(3) # prints "8"
print a(1) # prints "9"

Peter
 
P

Paul Rubin

Peter Otten said:
Should be

a = accum(3) # create accumulator holding 3
print a(2) # prints "5"
print a(3) # prints "8"
print a(1) # prints "9"

Oops, yes.
 
L

Leif K-Brooks

Paul said:
class accum:
def __init__(self, n):
self.s = n
def __call__(self, i):
self.s += i
return self.s

Just for fun, a full-blown class with documentation and the like:

class Accumulator(object):
"""This class implements a simple accumulator. Instate it with a
starting value, or it will default to 0. It can be called with
another value, which will be accumulated. The current value will
also be returned.

Example:
7
"""

__slots__ = '_value'

def __init__(self, value=0):
self._value = value

def __call__(self, value):
self._value += value
return self._value

def __str__(self):
return str(self._value)

def __repr__(self):
return "<Accumulator object with value %s>" % self._value
 
M

Michele Simionato

Leif K-Brooks said:
Just for fun, a full-blown class with documentation and the like:

class Accumulator(object):
"""This class implements a simple accumulator. Instate it with a
starting value, or it will default to 0. It can be called with
another value, which will be accumulated. The current value will
also be returned.

Example:

7
"""

__slots__ = '_value'

def __init__(self, value=0):
self._value = value

def __call__(self, value):
self._value += value
return self._value

def __str__(self):
return str(self._value)

def __repr__(self):
return "<Accumulator object with value %s>" % self._value

I just don't see the need to use __slots__ here. The first rule about __slots__
is: don't use them! OTOH the second rule (for expert only) is: don't use them!!

That's true for any optimization, isnt'it? ;)

Michele Simionato
 
S

Scott David Daniels

Paul said:
... The Pythonic way to do it is with a class instance:

class accum:
def __init__(self, n):
self.s = n
def __call__(self, i):
self.s += i
return self.s

a = accum(3)
(etc.)

however, for programmers comfortable with the Lisp idioms of using
internal lambdas, the class/object approach is cumbersome.

The way I'd do it is:

class accum:
def __init__(self, start):
self.runningtotal = start

def increment(self, value):
self.runningtotal += value
return self.runningtotal

a = accum(3).increment
Then you can use:
a(3) ...

That is, avoid magic names unless needed, and make the names obvious.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top