Re: using "private" parameters as static storage?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • J. Cliff Dyer

    Re: using "private" parameters as static storage?


    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:
    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 '

    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.
    He is using an object. Specifically, he's using a function object.
    Though perhaps you meant put it into a class.

    Here are a few essays into the matter
    >>def foo():
    .... foo._count += 1
    .... return ("spam " * foo.count).rstr ip()
    ....
    >>foo._count= 0
    >>foo()
    'spam'
    >>foo()
    'spam spam'
    >>>
    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.

    Attempt #2 -- put it in a decorator
    >>def add_counter(f):
    .... f._count = 0
    .... return f
    ....
    >>@add_counte r
    .... def foo():
    .... foo._count += 1
    .... return ("spam " * foo._count).rst rip()
    >>foo()
    'spam'
    >>foo()
    'spam spam'
    >>>
    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. 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):
    .... def __init__(self, counter_start=0 ):
    .... self._count = counter_start
    .... def __call__(self):
    .... self._count += 1
    .... return ("spam " * self._count).rs trip()
    ....
    >>foo = Foo()
    >>foo()
    'spam'
    >>foo()
    'spam spam'
    >>>
    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). 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


Working...