using "private" parameters as static storage?

J. Cliff Dyer jcd at sdf.lonestar.org
Thu Nov 13 13:32:22 EST 2008


On Thu, 2008-11-13 at 09:38 -0800, Matimus wrote:
> On Nov 13, 9:16 am, Joe Strout <j... at strout.net> wrote:
> > 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()
> > 'spam spam '
> >
> 
> Don't Do this, it is confusing and there are definitely (many) better
> facilities in python for handling saved state.
> 
> 
> > 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.count=0
> >       spam2.count += 1
> >       return "spam2 " * spam2.count
> 
> 
> This is definitely preferred over the first. However the preferred
> method is just to use a class. Preserving state is what classes are
> for.
> 

Preserving state is what *objects* are for.  Even the builtins have
state to be preserved (list.__len__, func.func_code, for example).

Classes are for creating custom objects.  

> >>> class Spam(object):
> ...     def __init__(self):
> ...         self._count = 0
> ...     def spam(self):
> ...         self._count += 1
> ...         return " ".join("spam" for _ in xrange(self._count))
> ...

Oh of course.  This is a much cleaner way to return the response than
the one I used.  (FYI, I used: `return ("spam " * self._count).rstrip()`
and I didn't like the rstrip even when I was doing it.  Dunno why I
didn't think of it.)  


> >>> class Spam(object):
> ...     def __init__(self):
> ...         self._count = 0
> ...
> ...     def spam(self):
> ...         self._count += 1
> ...         return " ".join("spam" for _ in xrange(self._count))
> ...
> ...     __call__ = spam
> ...

Interesting.  I hadn't thought of making __call__ a synonym for an
existing method.  I think I like that, but I'm not quite sure.  There's
something that nags at me about having two ways to do the same thing,
but I like giving the method a more descriptive name than __call__.

Cheers,
Cliff





More information about the Python-list mailing list