Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Newbie: anything resembling static?

0 views
Skip to first unread message

anton wilson

unread,
Jan 29, 2003, 3:16:48 PM1/29/03
to

Is there any way of imitating "static" C function variables without having to
define the variable as a global? I just want persistent function variables
but i want them to be local to the function namespace. :S

Anton

John Roth

unread,
Jan 29, 2003, 4:28:35 PM1/29/03
to

"anton wilson" <anton....@camotion.com> wrote in message
news:mailman.1043870531...@python.org...

Not obviously. The two ways of doing something similar are:

1. Use a class; the class instance will keep persistant variables

2. Use a simple generator. All of the function's variables
are persistant across calls to the generator.

HTH.

John Roth
>


Alex Martelli

unread,
Jan 29, 2003, 4:56:21 PM1/29/03
to
anton wilson wrote:

There are several ways you can approximate this effect, e.g.:

def one(fakedefault=[]):
fakedefault.append('x')
return ''.join(fakedefault)

def two():
try: two.staticvar.append('x')
except AttributeError: two.staticvar = ['x']
return ''.join(two.staticvar)

def three():
staticvar = []
def innerthree():
staticvar.append('x')
return ''.join(staticvar)
global three
three = innerthree
return innerthree()

def four():
four.staticvar.append('x')
return ''.join(four.staticvar)
four.staticvar = []

def five():
staticvar = []
def innerfive():
staticvar.append('x')
return ''.join(staticvar)
return innerfive
five = five()


simplest, of course, is to drop the arbitrary "local to the function
namespace" prerequisite in favour of a global with a suitable
name convention:

_six_staticvar = []
def six():
_six_staticvar.append('x')
return ''.join(_six_staticvar)


Anyway, all of these functions are to be called without arguments,
and each call returns a string of one more 'x' than the previous
one via different approximations to a "function static var".


Alex

Mongryong

unread,
Jan 29, 2003, 5:48:01 PM1/29/03
to

One, if not, the only reason, for having a static variable in a function
is if you wanted to conserve 'global' memory space. For example, if the
function with the static variable is never called in your application,
'global' memory is not wastefully allocated for that variable. Event
callback functions are great examples of when to use static function
variables.

If you're just concern about namespace issues, you're much better off to
use a global variable with a unique naming scheme.

But if you're reasons for wanting a static function variable is to
conserve wasting 'global' memory (as I've described above), you're
better to use a approach like this:

__callback_static_var = None
def callback(x):
if __callback_static_var is None:
__callback_static_var = CreateSomeStaticVar()

...process

In fact, this is similar to what C/C++ do in their implementation of
static function variables. The only difference being that in Python the
object is always created on 'heap'.

Hope that helps :)

Erik Max Francis

unread,
Jan 29, 2003, 10:03:42 PM1/29/03
to
anton wilson wrote:

Not explicitly. You can use a global but prefix it with an underscore
(a convention in Python that says "hands off"). You could also include
an additional argument with a (mutable) default value which you don't
mention in your API and use it that way, but I personally would
discourage that idiom for this usage since I find it to be a little
unclear.

--
Erik Max Francis / m...@alcyone.com / http://www.alcyone.com/max/
__ San Jose, CA, USA / 37 20 N 121 53 W / &tSftDotIotE
/ \ The work will teach you how to do it.
\__/ (an Estonian proverb)
Python chess module / http://www.alcyone.com/pyos/chess/
A chess game adjudicator in Python.

Terry Reedy

unread,
Jan 30, 2003, 1:44:19 AM1/30/03
to

anton wilson wrote:

> Is there any way of imitating "static" C function variables without
> having to
> define the variable as a global? I just want persistent function
> variables
> but i want them to be local to the function namespace. :S

Since you said 'imitate', yes. Write a class with __init__() to
initialize the statics and __call__() to make the instances callible.
Don't get hung up on the use of 'class' instead of 'def' to introduce
the block, or the fact that 'class' can be used for more than just
writing a function with persistent local vars. Example:

class hello:
def __init__(self):
self.cnt = 0
def __call__(self):
self.cnt += 1
print "Hello, this is call number %d" % (self.cnt,)

>>> f=hello()
>>> f()
Hello, this is call number 1
>>> f()
Hello, this is call number 2
>>> f()
Hello, this is call number 3

Terry J. Reedy


Tom

unread,
Feb 1, 2003, 4:05:09 PM2/1/03
to
Alex Martelli <al...@aleax.it> wrote in message news:<96YZ9.102138$0v.29...@news1.tin.it>...

> anton wilson wrote:
>
> > Is there any way of imitating "static" C function variables without having
> > to define the variable as a global? I just want persistent function
> > variables but i want them to be local to the function namespace. :S

<alex>

>
> There are several ways you can approximate this effect, e.g.:
>

<snip>

> def five():
> staticvar = []
> def innerfive():
> staticvar.append('x')
> return ''.join(staticvar)
> return innerfive
> five = five()

I've played around with the several options in Alex's msg and learned
some things I didn't know about nested scopes. (Thanks, Alex.) I
also read PEP 227 (and understood many parts of it), but I still have
one question: after I've called the function 'five' several times, is
there a way to see the current value of 'staticvar' in an interactive
session?

Something like:
------------------------------
>>> five()
'x'
>>> five()
'xx'
>>> five()
'xxx'
>>>
>>> five.innerfive.staticvar
Traceback (most recent call last):
File "<interactive input>", line 1, in ?
AttributeError: 'function' object has no attribute 'innerfive'
>>>
------------------------------

I understand why 'five.innerfive.staticvar' doesn't work. What will?
Don't have any use case in mind, just curious.

TIA,
Tom

Mongryong

unread,
Feb 1, 2003, 4:27:32 PM2/1/03
to
On Sat, 2003-02-01 at 16:05, Tom wrote:
>
> > def five():
> > staticvar = []
> > def innerfive():
> > staticvar.append('x')
> > return ''.join(staticvar)
> > return innerfive
> > five = five()
>
> one question: after I've called the function 'five' several times, is
> there a way to see the current value of 'staticvar' in an interactive
> session?
>
def outer():
static = []
def inner():
static.append('x')
return ''.join(static)
return inner, static

>>> f, s = outer()
>>> f()
'x'
>>> f()
'xx'
>>> s
['x', 'x']

Terry Reedy

unread,
Feb 1, 2003, 5:37:36 PM2/1/03
to

"Tom" <nonotre...@yahoo.com> wrote in message
news:f1d59fef.03020...@posting.google.com...

> Alex Martelli <al...@aleax.it> wrote in message
news:<96YZ9.102138$0v.29...@news1.tin.it>...
> > def five():
> > staticvar = []
> > def innerfive():
> > staticvar.append('x')
> > return ''.join(staticvar)
> > return innerfive
> > five = five()
>
> I've played around with the several options in Alex's msg and
learned
> some things I didn't know about nested scopes. (Thanks, Alex.) I
> also read PEP 227 (and understood many parts of it), but I still
have
> one question: after I've called the function 'five' several times,
is
> there a way to see the current value of 'staticvar' in an
interactive
> session?

To do this (without making innerfive global), you should rewrite above
as class with __call__, as I believe I posted before.

TJR


Alex Martelli

unread,
Feb 2, 2003, 5:43:56 AM2/2/03
to
Tom wrote:
...

>> def five():
>> staticvar = []
>> def innerfive():
>> staticvar.append('x')
>> return ''.join(staticvar)
>> return innerfive
>> five = five()
>
> I've played around with the several options in Alex's msg and learned
> some things I didn't know about nested scopes. (Thanks, Alex.) I

You're welcome!

> also read PEP 227 (and understood many parts of it), but I still have
> one question: after I've called the function 'five' several times, is
> there a way to see the current value of 'staticvar' in an interactive
> session?

I don't think there's any way to get back to it (I haven't looked
deeply into it and would love to be proved wrong!): five does
know the names of its free variables, but their values it gets
via a "cell" object that, AFAIK, offers no accessibility from Python:

>>> five.func_code.co_freevars
('staticvar',)
>>> five.func_closure
(<cell at 0x4019629c: list object at 0x401b7d8c>,)
>>> dir(five.func_closure[0])
['__class__', '__cmp__', '__delattr__', '__doc__', '__getattribute__',
'__hash__', '__init__', '__new__', '__reduce__', '__repr__',
'__setattr__', '__str__']


> I understand why 'five.innerfive.staticvar' doesn't work. What will?
> Don't have any use case in mind, just curious.

If you DO need more sophisticated access to a bundle of
code and data, compared with what simple closures afford,
then it may be worth the slight complication of defining
a class for the purpose, as others have suggested: a class
is the "royal road" to bundling code and data for general
purposes -- closures only simplify your life for simple
(but important) special cases.

That much being said, it doesn't take much to tweak the
code to give you what you want -- just add ONE line...:

>> def five():
>> staticvar = []
>> def innerfive():
>> staticvar.append('x')
>> return ''.join(staticvar)

innerfive.staticvar = staticvar


>> return innerfive
>> five = five()

there -- NOW you can check on five.staticvar from the interactive
session, or wherever -- NOT five.innerfive.whatever -- the _name_
"innerfive" has now disappeared, as it was a local name of the
outer function whose name ('five') we've rebound to the inner...


Alex

Phil Rittenhouse

unread,
Feb 10, 2003, 1:31:24 PM2/10/03
to
Erik Max Francis <m...@alcyone.com> wrote in message news:<3E38960E...@alcyone.com>...

> anton wilson wrote:
>
> > Is there any way of imitating "static" C function variables without
> > having to
> > define the variable as a global? I just want persistent function
> > variables
> > but i want them to be local to the function namespace. :S
>
> Not explicitly. You can use a global but prefix it with an underscore
> (a convention in Python that says "hands off").

What I've been wondering lately is: could we add a 'static' keyword
to the language to accomplish the same thing?

You would use it in a way similar to the 'global' keyword, for example:

def foo():
static count = 0
print count

Under the covers Python would create a global for count but with a mangled
name, like _foo_count. If it already exists from a previous call, it would
do nothing, so assignments would only happen once.

The only other change would be in the variable lookups. As before Python
would search the local dictionary first, and then the global, but now
when it searches the global dictionary, it would first look for the mangled
name before looking for the unmangled name.

It's just sugar, but I think it looks cleaner. Of course, as with any
such change, you'll break anyone's code that uses the name static.

Comments?
Phil
-----------------
This email address will self-destruct in 30 days.

Magnus Lie Hetland

unread,
Feb 10, 2003, 11:16:05 PM2/10/03
to
In article <4da3e801.03021...@posting.google.com>, Phil
Rittenhouse wrote:
[snip]

>What I've been wondering lately is: could we add a 'static' keyword
>to the language to accomplish the same thing?
>
>You would use it in a way similar to the 'global' keyword, for example:
>
>def foo():
> static count = 0
> print count

This sort of local state is specifically what objects are for... I'd
rather advocate using them than adding a keyword for this...

However, if you want to simulate statics, default arguments are a
possibility:

def foo(count=[0]):
print count[0]
count[0] += 1

Default arguments are initialized when the functions are defined, and
may be manipulated subsequently (and are stored just like static
variables). Not very clean/elegant, IMO, but possible...

--
Magnus Lie Hetland "Nothing shocks me. I'm a scientist."
http://hetland.org -- Indiana Jones

Phil Rittenhouse

unread,
Feb 11, 2003, 3:53:52 PM2/11/03
to
> >def foo():
> > static count = 0
> > print count
>
> This sort of local state is specifically what objects are for... I'd
> rather advocate using them than adding a keyword for this...

I'm sure that is true in many cases, but is it always true?
I'm thinking about something like a function to send a byte out
a serial port. The first time it's called it needs to initialize
the UART, but after that it doesn't. Something like:

def send_byte(x):
static initialized = False
if not initialized:
do_init()
initialized = True
xmit(x)

If you used this function the way you might use print() for debugging
purposes, it might be called in hundreds of places in a large project.
If you wrapped it in a class, you'd have to take care of creating the object
before anyone calls it and sharing that object around somehow so everyone
can access it. It seems like a lot of complexity for what is supposed
to be a very simple task.

I'll admit I'm no OO guru, so if there's a better way to do it, let me know.

Thanks!
Phil

Rene Pijlman

unread,
Feb 11, 2003, 4:08:31 PM2/11/03
to
Phil Rittenhouse:
[static variable in function]

>If you wrapped it in a class, you'd have to take care of creating the object
>before anyone calls it and sharing that object around somehow so everyone
>can access it. It seems like a lot of complexity for what is supposed
>to be a very simple task.

Yes. Guido's answer was that you should simply make it a
module-global variable:

"In that case, consider using a module-global variable, e.g.:

ncalls = 0

def myfunction(arg):
global ncalls
ncalls = ncalls + 1
...your code goes here...

Because Python's globals are module-global, not program-global,
this is generally a safe practice."
http://groups.google.com/groups?q=static+group:comp.lang.python+author:guido&hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=199806221337.JAA03354%40eric.CNRI.Reston.Va.US&rnum=4

--
René Pijlman

Wat wil jij leren? http://www.leren.nl

Nick Vargish

unread,
Feb 11, 2003, 6:12:07 PM2/11/03
to
ph...@dspfactory.com (Phil Rittenhouse) writes:

> I'm thinking about something like a function to send a byte out
> a serial port. The first time it's called it needs to initialize
> the UART, but after that it doesn't.

This problem is exactly where classes will help:


class SerialPort:
__shared_state = {}
def __init__(self, address):
self.__dict__ = self.__shared_state
self.initialized = False
# other stuff to set up the serial port
def send_byte(self, x):
if not self.initialided:
self.initialize()
self.xmit(x)
def initialize(self):
# initialize the UART
self.initialized = True

> If you used this function the way you might use print() for debugging
> purposes, it might be called in hundreds of places in a large project.
> If you wrapped it in a class, you'd have to take care of creating the object
> before anyone calls it and sharing that object around somehow so everyone
> can access it.

That's what the __shared_state bit is all about. It's a "Borg" object;
each time you instantiate a SerialPort object, it will be the same
critter:

(http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66531)

Nick

--
# sigmask.py || version 0.2 || 2003-01-07 || Feed this to your Python.
print reduce(lambda x,y:x+chr(ord(y)-1),'Ojdl!Wbshjti!=obwAqbusjpu/ofu?','')

Paul Rubin

unread,
Feb 11, 2003, 6:25:28 PM2/11/03
to
ph...@dspfactory.com (Phil Rittenhouse) writes:
> def send_byte(x): ...

> static initialized = False
> if not initialized:
> do_init()
> initialized = True
> xmit(x)
>
> If you used this function the way you might use print() for debugging
> purposes, it might be called in hundreds of places in a large project.
> If you wrapped it in a class, you'd have to take care of creating the object
> before anyone calls it and sharing that object around somehow so everyone
> can access it. It seems like a lot of complexity for what is supposed
> to be a very simple task.

Sharing the class instance around doesn't seem any harder (or any
different) than sharing the function object around. If you run
something like

class _port:
def __init__(self):
self.initialized = false
def do_init(self):
self.initialized = true
...
def send_byte(self, x):
if not self.initialized:
self.do_init()
xmit(x)

send_byte = _port().send_byte

then you can use send_byte just as in your earlier definition.

Jp Calderone

unread,
Feb 11, 2003, 7:27:12 PM2/11/03
to

class SerialBlob:
def __init__(self):
self.initialize()
def initialize(self):
# do stuff
def send_byte(self, x):
xmit(x)


> Thanks!
> Phil
> --
> http://mail.python.org/mailman/listinfo/python-list

--
| This
| signature
| intentionally
| 8 lines
| long.
| (So sue me)
---
--
up 3 days, 4:28, 7 users, load average: 0.00, 0.02, 0.12

Phil Rittenhouse

unread,
Feb 12, 2003, 10:15:38 AM2/12/03
to
Coooool.

I hadn't quite grok'd that the class variables were shared
among all instances. That makes things much easier.

Thanks!
Phil


Nick Vargish <n...@adams.patriot.net> wrote in message news:<yyy7kc6...@adams.patriot.net>...

Robin Munn

unread,
Feb 12, 2003, 6:10:32 PM2/12/03
to
Phil Rittenhouse <ph...@dspfactory.com> wrote:
> Coooool.
>
> I hadn't quite grok'd that the class variables were shared
> among all instances. That makes things much easier.
>
> Thanks!
> Phil

This has very little to do with your question, but please don't top-post
like that. Top-posting (writing your response at the top of the post,
with the original text quoted in full below) takes up unnecessary
bandwidth and makes it hard to follow the thread of question and
response. It's usually considered polite to intersperse your response
with the original text, putting answers right below the question they
answer, and trim any material that's not relevant to what you're
responsing to.

Thanks.

[SNIP unnecessary full quote]

--
Robin Munn <rm...@pobox.com>
http://www.rmunn.com/
PGP key ID: 0x6AFB6838 50FF 2478 CFFB 081A 8338 54F7 845D ACFD 6AFB 6838

0 new messages