By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,235 Members | 1,057 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 440,235 IT Pros & Developers. It's quick & easy.

using "private" parameters as static storage?

P: n/a
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.count=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?

Best,
- Joe
Nov 13 '08 #1
Share this Question
Share on Google+
16 Replies


P: n/a
On Nov 13, 9:16*am, Joe Strout <j...@strout.netwrote:
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.
>>class Spam(object):
.... def __init__(self):
.... self._count = 0
.... def spam(self):
.... self._count += 1
.... return " ".join("spam" for _ in xrange(self._count))
....
>>x = Spam()
print x.spam()
spam
>>print x.spam()
spam spam
>>print x.spam()
spam spam spam

It also gives you the ability to have two compleately separate
instances of the same state machine.
>>y = Spam()
print y.spam()
spam
>>print y.spam()
spam spam
>>print y.spam()
spam spam spam
>>>
You can use it like a function if you need to for convenience or
backwards compatibility.:
>>spam = Spam().spam
print spam()
spam
>>print spam()
spam spam
>>print spam()
spam spam spam

Or:
>>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
....
>>spam = Spam()
print spam()
spam
>>print spam()
spam spam
>>print spam()
spam spam spam
Matt
Nov 13 '08 #2

P: n/a
On Thu, 2008-11-13 at 09:38 -0800, Matimus wrote:
On Nov 13, 9:16 am, Joe Strout <j...@strout.netwrote:
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
Nov 13 '08 #3

P: n/a
On Nov 13, 11:32 am, "J. Cliff Dyer" <j...@sdf.lonestar.orgwrote:
On Thu, 2008-11-13 at 09:38 -0800, Matimus wrote:
On Nov 13, 9:16 am, Joe Strout <j...@strout.netwrote:
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.
Not exclusively, generators also preserve state.

def _spam():
count = 1
while 1:
yield "spam " * count
count += 1
spam = _spam.next()

Nov 13 '08 #4

P: n/a
On Nov 13, 11:16*am, Joe Strout <j...@strout.netwrote:
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.count=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?
Worse yet, if you define a duplicate object at the same scope with the
same name later, it breaks all your references within the function to
itself.

One way around it, which I like the idea of but I'll be honest, I've
never used, is getting a function a 'self' parameter. You could make
it a dictionary or a blank container object, or just the function
itself.

@self_param
def spam( self ):
self._count[0] += 1 #<--- how to initialize?
return "spam " * self._count[0]

Only problem is, how do you initialize _count?

Perhaps 'self_param' can take some initializers, and just initialize
them off of **kwargs in the construction.

@self_param( _count= [] )
def spam( self ):
self._count[0] += 1
return "spam " * self._count[0]

Looks really pretty (imo), but untested.
Nov 13 '08 #5

P: n/a
On Nov 13, 3:08*pm, Aaron Brady <castiro...@gmail.comwrote:
On Nov 13, 11:16*am, Joe Strout <j...@strout.netwrote:


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.count=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?

Worse yet, if you define a duplicate object at the same scope with the
same name later, it breaks all your references within the function to
itself.

One way around it, which I like the idea of but I'll be honest, I've
never used, is getting a function a 'self' parameter. *You could make
it a dictionary or a blank container object, or just the function
itself.

@self_param
def spam( self ):
* * * self._count[0] += 1 *#<--- how to initialize?
* * * return "spam " * self._count[0]

Only problem is, how do you initialize _count?

Perhaps 'self_param' can take some initializers, and just initialize
them off of **kwargs in the construction.

@self_param( _count= [] )
def spam( self ):
* * * self._count[0] += 1
* * * return "spam " * self._count[0]

Looks really pretty (imo), but untested.- Hide quoted text -

- Show quoted text -
Initialization does not have to be in the body of the method.
>>def spam():
.... spam._count[0] += 1 #<--- how to initialize? see below
.... return "spam " * spam._count[0]
....
>>spam._count = [2] # just initialize it, and not necessarily to 0
spam()
'spam spam spam '
>>spam()
'spam spam spam spam '
>>spam()
'spam spam spam spam spam '
>>>
-- Paul
Nov 13 '08 #6

P: n/a
On 13 Nov, 18:16, Joe Strout <j...@strout.netwrote:
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.
Why not use a module global? It isn't hidden, but it is quite a clean
approach. Modifying your example...

spam_count = 0

def spam():
global spam_count
spam_count += 1
return "spam " * spam_count

[...]
This doesn't expose any uncleanliness outside the function at all.
I wouldn't be too worried about that. Although namespaces can become
somewhat crowded with all these extra names, there can be benefits in
exposing such names, too, but if you find this too annoying, it could
be advisable to collect these entries and put them in another
namespace, maybe a class or a module.

Paul
Nov 13 '08 #7

P: n/a
On Nov 13, 4:13*pm, Paul McGuire <pt...@austin.rr.comwrote:
On Nov 13, 3:08*pm, Aaron Brady <castiro...@gmail.comwrote:
On Nov 13, 11:16*am, Joe Strout <j...@strout.netwrote:
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.count=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?
Worse yet, if you define a duplicate object at the same scope with the
same name later, it breaks all your references within the function to
itself.
One way around it, which I like the idea of but I'll be honest, I've
never used, is getting a function a 'self' parameter. *You could make
it a dictionary or a blank container object, or just the function
itself.
@self_param
def spam( self ):
* * * self._count[0] += 1 *#<--- how to initialize?
* * * return "spam " * self._count[0]
Only problem is, how do you initialize _count?
Perhaps 'self_param' can take some initializers, and just initialize
them off of **kwargs in the construction.
@self_param( _count= [] )
def spam( self ):
* * * self._count[0] += 1
* * * return "spam " * self._count[0]
Looks really pretty (imo), but untested.- Hide quoted text -
- Show quoted text -

Initialization does not have to be in the body of the method.
>def spam():

... * * * spam._count[0] += 1 *#<--- how to initialize? see below
... * * * return "spam " * spam._count[0]
...>>spam._count = [2] # just initialize it, and not necessarily to 0
>spam()
'spam spam spam '
>spam()

'spam spam spam spam '
>spam()

'spam spam spam spam spam '

That is actually susceptible to a subtle kind of bug:
>>def spam( ):
.... spam._count[0] += 1
.... return "spam " * spam._count[0]
....
>>spam._count=[2]
spam()
'spam spam spam '
>>f= spam
f()
'spam spam spam spam '
>>spam= 'spam and eggs'
f()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in spam
AttributeError: 'str' object has no attribute '_count'

It would be worse if you assigned 'spam' to another function! Of
course one option is 'just don't do that', which is alright. Adding
the self parameter is just a second option, if you need the function
to change names. Though the decorator is a nice place for the
initialization.
Nov 13 '08 #8

P: n/a
Joe Strout <jo*@strout.netwrites:
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
This is precisely what classes are for: allowing functionality and
state to exist in a single object.
but not visible outside the method.
Bind the state to a name with a single leading underscore (‘_foo’),
which is the convention for “not part of the public interface”.
Don't look for hard access restrictions, though, because they don't
really exist in Python.

--
\ “I hope that after I die, people will say of me: ‘That guy sure |
`\ owed me a lot of money’.” —Jack Handey |
_o__) |
Ben Finney
Nov 14 '08 #9

P: n/a
Ben Finney wrote:
Joe Strout <jo*@strout.netwrites:
>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

This is precisely what classes are for: allowing functionality and
state to exist in a single object.
>but not visible outside the method.

Bind the state to a name with a single leading underscore (‘_foo’),
which is the convention for “not part of the public interface”.
Don't look for hard access restrictions, though, because they don't
really exist in Python.
Neither do typed variables, but that's not going to stop Joe ;-)

regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
Holden Web LLC http://www.holdenweb.com/

Nov 14 '08 #10

P: n/a
Aaron Brady <ca********@gmail.comwrites:
One way around it, which I like the idea of but I'll be honest, I've
never used, is getting a function a 'self' parameter. You could make
it a dictionary or a blank container object, or just the function
itself.

@self_param
def spam( self ):
self._count[0] += 1 #<--- how to initialize?
return "spam " * self._count[0]

Only problem is, how do you initialize _count?

Perhaps 'self_param' can take some initializers, and just initialize
them off of **kwargs in the construction.

@self_param( _count= [] )
def spam( self ):
self._count[0] += 1
return "spam " * self._count[0]

Looks really pretty (imo), but untested.
Rummaging through my ~/python/junk/ I found the almost exact same:

class NS(object):
def __init__(self, dict):
self.__dict__.update(dict)

def static(**vars):
ns = NS(vars)
def deco(f):
return lambda *args, **kwargs: f(ns, *args, **kwargs)
return deco

@static(ncalls=0, history=[])
def foo(ns, x):
ns.ncalls += 1
ns.history.append(x)
print "Number of calls: %s\nHistory:%s" % (ns.ncalls, ns.history)
>>foo(3)
Number of calls: 1
History:[3]
>>foo(5)
Number of calls: 2
History:[3, 5]
>>foo('spam')
Number of calls: 3
History:[3, 5, 'spam']
>>>
--
Arnaud
Nov 14 '08 #11

P: n/a
On Thu, 13 Nov 2008 10:16:59 -0700, Joe Strout 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]
This is a common trick, often used for things like caching. One major
advantage is that you are exposing the cache as an *optional* part of the
interface, which makes testing easier. For example, instead of a test
that looks something like this:
cache = get_access_to_secret_cache() # somehow
modify(cache)
result = function(arg)
restore(cache)
assert something_about(result)

you can simple do this:

result = function(arg, _cache=mycache)
assert something_about(result)
Periodically people complain that Python's mutable default argument
behaviour is a problem, and ask for it to be removed. I agree that it is
a Gotcha that trips up newbies, but it is far to useful to give up, and
simple caching is one such reason.

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 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?
I've used this myself, but to me it feels more icky than the semi-private
argument trick above.


--
Steven
Nov 14 '08 #12

P: n/a
On Thu, 13 Nov 2008 14:25:08 -0800, Paul Boddie wrote:
On 13 Nov, 18:16, Joe Strout <j...@strout.netwrote:
>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.

Why not use a module global? It isn't hidden, but it is quite a clean
approach. Modifying your example...
For some definition of "clean".

http://archive.eiffel.com/doc/manual...articles/joop/
globals.html

http://weblogs.asp.net/wallen/archiv...5/08/6750.aspx

Python globals aren't quite as bad, because they are merely global to a
module and not global to your entire application. Nevertheless, your
example is one of the *worst* usages for globals. See below.

spam_count = 0

def spam():
global spam_count
spam_count += 1
return "spam " * spam_count

[...]
>This doesn't expose any uncleanliness outside the function at all.
Nonsense. Any other function in the code can write to spam_count and
cause all sorts of havoc. Any function that needs to temporarily modify
spam_count needs to be careful to wrap it with a save and a restore:

n = spam_count
spam_count = 47
s = spam()
spam_count = n
This is precisely one of the anti-patterns that global variables
encourage, and one of the reasons why globals are rightly considered
harmful. Don't Do This.

--
Steven
Nov 14 '08 #13

P: n/a
Joe Strout a crit :
One thing I miss as I move from REALbasic to Python is the ability to
have static storage within a method
s/method/function/
-- 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.
It's indeed a hack. But it's a very common one, and
Naming the
parameter with an underscore "_count"
is also a pretty idiomatic way to warn that it's implementation-only.
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?
If it's really in a *method*, you can always use a class (or instance,
depending on concrete use case) attribute. Else, if you really insist on
cleanliness, you can define your own callable:

class Spammer(object):
def __init__(self):
self._count = 0
def __call__(self):
self._count += 1
return "spam " * self._count

spam = Spammer()

But this might be a little overkill for most concrete use case.

NB : you'll also have to implement __get__ if you want Spammer instances
to be used as methods.
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 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.
There's another drawback:

old_spam2 = spam2

def spam2():
print "yadda yadda", old_spam2()
Remember that Python functions are ordinary objects...

Nov 14 '08 #14

P: n/a
Matimus a crit :
On Nov 13, 9:16 am, Joe Strout <j...@strout.netwrote:
(snip)
>def spam2():
if not hasattr(spam2,'count'):spam2.count=0
spam2.count += 1
return "spam2 " * spam2.count


This is definitely preferred over the first.
I beg to disagree. This solution stores "count" on *whatever* the name
"spam2" resolves at runtime.

(snip)
Nov 14 '08 #15

P: n/a
On Nov 13, 2008, at 8:26 PM, Steven D'Aprano wrote:
>def spam(_count=[0]):
_count[0] += 1
return "spam " * _count[0]

This is a common trick, often used for things like caching. One major
advantage is that you are exposing the cache as an *optional* part
of the
interface, which makes testing easier. For example, instead of a test
that looks something like this:

cache = get_access_to_secret_cache() # somehow
modify(cache)
result = function(arg)
restore(cache)
assert something_about(result)

you can simple do this:

result = function(arg, _cache=mycache)
assert something_about(result)
That's a very good point. I'd been working under the assumption that
any outside mucking with the cache was a Bad Thing, but for testing,
it can be darned helpful. And this is a very safe form of mucking; it
doesn't actually affect the "real" cache at all, but just substitutes
a temporary one.

Thanks also for pointing out that this is a common trick -- after all
the attacks on the very idea last night, I was wondering if I were off
alone in the woods again.
>def spam2():
if not hasattr(spam2,'count'):spam2.count=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?

I've used this myself, but to me it feels more icky than the semi-
private
argument trick above.
Thanks for the feedback.

Best,
- Joe

Nov 14 '08 #16

P: n/a
On Nov 13, 4:23*pm, Arnaud Delobelle <arno...@googlemail.comwrote:
def static(**vars):
* * ns = NS(vars)
* * def deco(f):
* * * * return lambda *args, **kwargs: f(ns, *args, **kwargs)
* * return deco

@static(ncalls=0, history=[])
def foo(ns, x):
* *ns.ncalls += 1
* *ns.history.append(x)
* *print "Number of calls: %s\nHistory:%s" % (ns.ncalls, ns.history)
One could even add 'ns' as an attribute of 'f', so that the statics
were visible from the outside: 'foo.ns.ncalls'.
Nov 14 '08 #17

This discussion thread is closed

Replies have been disabled for this discussion.