using "private" parameters as static storage?

Joe Strout joe at strout.net
Thu Nov 13 21:52:13 EST 2008


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




More information about the Python-list mailing list