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