On Nov 13, 2008, at 11:15 AM, J. Cliff Dyer wrote:

Here are a few essays into the matter

def foo():
...     foo._count += 1
...     return ("spam " * foo.count).rstrip()

Simple and straightforward, and _count is still encapsulated in the
function, but it's kind of ugly, because when the function has been
defined, it is not functional.

Right, though the hasattr() check I put in my version of this approach takes care of that.

Attempt #2 -- put it in a decorator

def add_counter(f):
...     f._count = 0
...     return f
...
@add_counter
... def foo():
...     foo._count += 1
...     return ("spam " * foo._count).rstrip()

Now THAT is something that hadn't occurred to me! I haven't really studied decorators yet (and I'm pretty sure Python didn't have them when I was last into it a decade ago). This is an interesting solution.

Now it's complete as soon as the function is defined, but the decorator
is tightly bound to the function, in its use of _count.  I find that
kind of ugly.

True. And we have two functions where we really only wanted one -- that's probably worse than just having a function plus a module-level variable. Unless, perhaps, we could make a generic "has_cache" decorator that can be reused in any method that needs some static storage.

Try three.  Let's put it in a class:

class Foo(object):
...     def __init__(self, counter_start=0):
...         self._count = counter_start
...     def __call__(self):
...         self._count += 1
...         return ("spam " * self._count).rstrip()

At first I thought this suggestion was just to add an instance variable to whatever class my method was already in, which violates encapsulation at the level I'm after. But now I see this is is something more subtle: you've made a callable object. We'd presumably combine this with a Singleton pattern to get the desired semantics. This is clever, but an awful lot of code for such a simple need.

Essentially, this has the same behavior as the other two. But it looks cleaner, and you don't have to worry about coupling separate functions,
or refering to a function by name within itself (because you have self
to work with).

True. Pity there isn't a way for a function to get a reference to itself except by name. Still, when you rename a method, you're going to have to update all the callers anyway -- updating a couple of extra references within the method is not that much extra effort.

All of these approaches may turn out to be more trouble than they're worth; a module variable isn't THAT ugly. But it's nice to have some options.

At any rate, you (and rurpy) have taken the time to consider the question I was actually asking, instead of arguing with me whether I should be asking it. I really appreciate that. Your suggestions are helpful and have taught me some new Python tricks. Thanks very much!

Best,
- Joe

--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to