On Thu, 2008-11-13 at 11:19 -0600, Chris Mellon wrote:
On Thu, Nov 13, 2008 at 11:16 AM, Joe Strout <joe@strout.net wrote:
>
Static storage is a way of preserving state. Objects are a way of
encapsulating state and behavior. Use an object.
One thing I miss as I move from REALbasic to Python is the ability to have
static storage within a method -- i.e. storage that is persistent between
calls, but not visible outside the method. I frequently use this for such
things as caching, or for keeping track of how many objects a factory
function has created, and so on.
Today it occurred to me to use a mutable object as the default value of a
parameter. A simple example:
def spam(_count=[0]):
_count[0] += 1
return "spam " * _count[0]
'spam '
'spam spam '
This appears to work fine, but it feels a little unclean, having stuff in
the method signature that is only meant for internal use. Naming the
parameter with an underscore "_count" makes me feel a little better about
it. But then, adding something to the module namespace just for use by one
function seems unclean too.
What are your opinions on this idiom? Is there another solution people
generally prefer?
Ooh, for a change I had another thought BEFORE hitting Send rather than
after. Here's another trick:
def spam2():
if not hasattr(spam2,' count'):spam2.c ount=0
spam2.count += 1
return "spam2 " * spam2.count
This doesn't expose any uncleanliness outside the function at all. The
drawback is that the name of the function has to appear several times within
itself, so if I rename the function, I have to remember to change those
references too. But then, if I renamed a function, I'd have to change all
the callers anyway. So maybe this is better. What do y'all think?
static storage within a method -- i.e. storage that is persistent between
calls, but not visible outside the method. I frequently use this for such
things as caching, or for keeping track of how many objects a factory
function has created, and so on.
Today it occurred to me to use a mutable object as the default value of a
parameter. A simple example:
def spam(_count=[0]):
_count[0] += 1
return "spam " * _count[0]
>>spam()
>>spam()
This appears to work fine, but it feels a little unclean, having stuff in
the method signature that is only meant for internal use. Naming the
parameter with an underscore "_count" makes me feel a little better about
it. But then, adding something to the module namespace just for use by one
function seems unclean too.
What are your opinions on this idiom? Is there another solution people
generally prefer?
Ooh, for a change I had another thought BEFORE hitting Send rather than
after. Here's another trick:
def spam2():
if not hasattr(spam2,' count'):spam2.c ount=0
spam2.count += 1
return "spam2 " * spam2.count
This doesn't expose any uncleanliness outside the function at all. The
drawback is that the name of the function has to appear several times within
itself, so if I rename the function, I have to remember to change those
references too. But then, if I renamed a function, I'd have to change all
the callers anyway. So maybe this is better. What do y'all think?
Static storage is a way of preserving state. Objects are a way of
encapsulating state and behavior. Use an object.
Though perhaps you meant put it into a class.
Here are a few essays into the matter
>>def foo():
.... return ("spam " * foo.count).rstr ip()
....
>>foo._count= 0
>>foo()
>>foo()
>>foo()
>>>
function, but it's kind of ugly, because when the function has been
defined, it is not functional.
Attempt #2 -- put it in a decorator
>>def add_counter(f):
.... return f
....
>>@add_counte r
.... foo._count += 1
.... return ("spam " * foo._count).rst rip()
>>foo()
>>foo()
>>>
is tightly bound to the function, in its use of _count. I find that
kind of ugly. This is the first decorator I've written that doesn't
define a function inside itself.
Try three. Let's put it in a class:
>>class Foo(object):
.... self._count = counter_start
.... def __call__(self):
.... self._count += 1
.... return ("spam " * self._count).rs trip()
....
>>foo = Foo()
>>foo()
>>foo()
>>foo()
>>>
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). But the "object" semantics are essentially the same, and
state is just as legitimately preserved on a function object as a Foo
object.
Cheers,
Cliff