473,395 Members | 1,823 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,395 software developers and data experts.

Pythonic way to do static local variables?

I've a function that needs to maintain an ordered sequence between
calls.

In C or C++, I'd declare the pointer (or collection object) static at
the function scope.

What's the Pythonic way to do this?

Is there a better solution than putting the sequence at module scope?

Thanks.

Jul 19 '05 #1
11 5015
> I've a function that needs to maintain an ordered sequence between
calls.

In C or C++, I'd declare the pointer (or collection object) static at
the function scope.

What's the Pythonic way to do this?

Is there a better solution than putting the sequence at module scope?


Yes, there is; it's called "object oriented programming". In general,
whenever you find that one or more functions have to access a context
that is not passed in explicitly as arguments, the proper (pythonic and
non-pythonic) way is to define them as a method in a class that stores
this context.

class Foo(object):
def __init__(self):
self._context = # something

def method(self):
x = self._context
# do stuff
self._context.update()
Another solution is function/method attributes. This is handy if OO
seems an overkill for a single function, or in case of methods, if you
don't want to pollute the instance namespace with something used by a
single method:

def foo():
# foo.x is like a C static
try: foo.x +=1
except AttributeError:
foo.x = 1
return foo.x

for i in xrange(10): print foo()

if foo() is a method, it becomes a little more cumbersome, first
because you have to refer to the class name and (less obviously)
because user defined attributes are not allowed in instance methods (I
wonder why); you have to refer to the wrapped function:

class Foo(object):
def foo(self):
try: Foo.foo.im_func.x += 1
except AttributeError:
Foo.foo.im_func.x = 1
return Foo.foo.x

foo = Foo().foo
for i in xrange(10): print foo()
Hope this helps,

George

Jul 19 '05 #2
Well, if you're a c++ programmer, then you've probably ran into
`functors' at one time or another. You can emulate it by making a
python object that is `callable'.

class functor:
def __init__(self):
self.ordered_sequence = [1, 2, 3, 4, 5]
def __call__(self, arg1, arg2):
self.ordered_sequence.extend((arg1,arg2))
self.ordered_sequence.sort()
f = functor()
f(3,5)
f.ordered_sequence
[1, 2, 3, 3, 4, 5, 5]

Hope that helps some.
jw

On 4/25/05, Charles Krug <cd****@worldnet.att.net> wrote: I've a function that needs to maintain an ordered sequence between
calls.

In C or C++, I'd declare the pointer (or collection object) static at
the function scope.

What's the Pythonic way to do this?

Is there a better solution than putting the sequence at module scope?

Thanks.

--
http://mail.python.org/mailman/listinfo/python-list

Jul 19 '05 #3
Charles Krug wrote:
I've a function that needs to maintain an ordered sequence between
calls.

In C or C++, I'd declare the pointer (or collection object) static at
the function scope.

What's the Pythonic way to do this?

Is there a better solution than putting the sequence at module scope?

Thanks.


You might want a generator. Search for yield keyword.
Regards,
Nicolas
Jul 19 '05 #4
Charles Krug <cd****@worldnet.att.net> writes:
I've a function that needs to maintain an ordered sequence between
calls.

In C or C++, I'd declare the pointer (or collection object) static at
the function scope.

What's the Pythonic way to do this?

Is there a better solution than putting the sequence at module scope?


I'm not sure what you mean by "an ordered sequence". Assuming that a
static counter variable will do the trick (i.e. - it's values will
sequence across calls), you can do this in a number of ways:

1) Use a class:

class counterClass:
def __init__(self):
self.count = 1
def __call__(self):
self.count = self.count + 1

counterFunc = counterClass()

2) Use an instance variable of the function:

def counterFunc():
foo.counter = foo.counter + 1
foo.counter = 1

You ought to be able to do this with closures as well, but I couldn't
seem to get that to work.

<mike
--
Mike Meyer <mw*@mired.org> http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
Jul 19 '05 #5
On Mon, 25 Apr 2005 21:30:18 -0500, Jaime Wyant
<pr***********@gmail.com> wrote:
Well, if you're a c++ programmer,
Well, my forte is embedded systems and device controls . . .
then you've probably ran into
`functors' at one time or another. You can emulate it by making a
python object that is `callable'.

class functor:
def __init__(self):
self.ordered_sequence = [1, 2, 3, 4, 5]
def __call__(self, arg1, arg2):
self.ordered_sequence.extend((arg1,arg2))
self.ordered_sequence.sort()


"ordered" in this case doesn't mean "sorted." . . .
8-)

It's the set of filter coefficients and cumulative remainders for an
overlap add convolution. Sorting would be . . . bad. Like crossing the
streams bad.

Both of these techniques look promising here.
Thanks
Jul 19 '05 #6

"Charles Krug" <cd****@worldnet.att.net> wrote in message
news:7U*********************@bgtnsc05-news.ops.worldnet.att.net...
Both of these techniques look promising here.


Here a third, the closure approach (obviously not directly tested):

def func_with_static(datalist):
def real_func(otherargs):
<code that uses datalist>
return real_func

func1 = func_with_static([.1, 99, 1e-10,...])

If needed, real_func can *modify* (but not *rebind*) datalist.
Unlike the attribute approach, but like the class approach, you can
simultaneously have have multiple closures with different static data

func2 = func_with_static([.2, 152, 1e-9, ...])

Terry J. Reedy

Jul 19 '05 #7
Terry Reedy wrote:
"Charles Krug" <cd****@worldnet.att.net> wrote in message
news:7U*********************@bgtnsc05-news.ops.worldnet.att.net...
Both of these techniques look promising here.

Here a third, the closure approach (obviously not directly tested):

Just for grins, here's a fourth approach, using the descriptor protocol
def func_with_state(state,a): ... state.append(a)
... return state
... f = func_with_state.__get__([])
f(1) [1] f(2) [1, 2] f(3) [1, 2, 3]


Michael

Jul 19 '05 #8
A quick, hackish way to keep a static variable is to declare it as a
parameter and give it a default value. The parameter list is evaluated
when the function is compiled, not when it is called. The underscores
are added as per convention to indicate that the variable is
special/private.

Example-

def cumulative_sum(arg, __static__ = []):
__static__.append(arg)
return reduce(lambda a,b: a + b, __static__)

#-------------------
cumulative_sum(1) 1 cumulative_sum(1) 2 cumulative_sum(1)

3

Jul 19 '05 #9
A quick, hackish way to keep a static variable is to declare it as a
parameter and give it a default value. The parameter list is evaluated
when the function is compiled, not when it is called. The underscores
are added as per convention to indicate that the variable is
special/private.

Example-

def cumulative_sum(arg, __static__ = []):
__static__.append(arg)
return reduce(lambda a,b: a + b, __static__)

#-------------------
cumulative_sum(1) 1 cumulative_sum(1) 2 cumulative_sum(1)

3

Jul 19 '05 #10
On Tue, 26 Apr 2005 10:26:51 -0700, Michael Spencer <ma**@telcopartners.com> wrote:
Terry Reedy wrote:
"Charles Krug" <cd****@worldnet.att.net> wrote in message
news:7U*********************@bgtnsc05-news.ops.worldnet.att.net...
Both of these techniques look promising here.

Here a third, the closure approach (obviously not directly tested):

Just for grins, here's a fourth approach, using the descriptor protocol
>>> def func_with_state(state,a): ... state.append(a)
... return state
... >>> f = func_with_state.__get__([])
>>> f(1) [1] >>> f(2) [1, 2] >>> f(3) [1, 2, 3] >>>

For those who don't recognize it, this is the mechanism that binds instances to
methods of their type to make bound methods. It's as if you had given list a
new method and picked up the bound method from an instance like [].func_with_state
def func_with_state(state, a): ... state.append(a)
... return state
... f = func_with_state.__get__([])
f <bound method ?.func_with_state of []>

The '?' is because we didn't supply the second argument to __get__, i.e., type([])
f = func_with_state.__get__([], list)
f <bound method list.func_with_state of []>
f.im_func <function func_with_state at 0x02EFD614> func_with_state <function func_with_state at 0x02EFD614>
For grins, here's a fifth approach (I'm assuming you counted correctly to the fourth ;-)
from ut.presets import presets
@presets(state=[]) ... def f(a):
... state.append(a)
... return state
... f(1) [1] f(2) [1, 2] f(3) [1, 2, 3]

This is a straight function, with byte-code hack preset of internal state as specified.
The disassemby shows [1, 2, 3] because that is the object referred to still. What would have
been a global reference got hacked to LOAD_FAST 1 (state) after preset from "constant".
import dis
dis.dis(f) 1 0 LOAD_CONST 1 ([1, 2, 3])
3 STORE_FAST 1 (state)

3 6 LOAD_FAST 1 (state)
9 LOAD_ATTR 1 (append)
12 LOAD_FAST 0 (a)
15 CALL_FUNCTION 1
18 POP_TOP

4 19 LOAD_FAST 1 (state)
22 RETURN_VALUE

To see the initial state, we have to re-decorate another instance of f:
@presets(state=[]) ... def f(a):
... state.append(a)
... return state
... dis.dis(f) 1 0 LOAD_CONST 1 ([])
3 STORE_FAST 1 (state)

3 6 LOAD_FAST 1 (state)
9 LOAD_ATTR 1 (append)
12 LOAD_FAST 0 (a)
15 CALL_FUNCTION 1
18 POP_TOP

Of course, we could put this inside a factory and pass the desired state
def factory(state): ... @presets(state=state)
... def f(a):
... state.append(a)
... return state
... return f
... f2 = factory([111,222])
f2('third') [111, 222, 'third'] dis.dis(f2) 2 0 LOAD_CONST 1 ([111, 222, 'third'])
3 STORE_FAST 1 (state)

4 6 LOAD_FAST 1 (state)
9 LOAD_ATTR 1 (append)
12 LOAD_FAST 0 (a)
15 CALL_FUNCTION 1
18 POP_TOP

5 19 LOAD_FAST 1 (state)
22 RETURN_VALUE dis.dis(factory('append will fail')) 2 0 LOAD_CONST 1 ('append will fail')
3 STORE_FAST 1 (state)

4 6 LOAD_FAST 1 (state)
9 LOAD_ATTR 1 (append)
12 LOAD_FAST 0 (a)
15 CALL_FUNCTION 1
18 POP_TOP

5 19 LOAD_FAST 1 (state)
22 RETURN_VALUE

Note that the function takes only one argument:
f2 <function f at 0x02EF841C> f2.func_code.co_argcount 1 f2(10, 'fails')

Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: f() takes exactly 1 argument (2 given)

Regards,
Bengt Richter
Jul 19 '05 #11
On 26 Apr 2005 13:58:23 -0700, "Lonnie Princehouse" <fi**************@gmail.com> wrote:
A quick, hackish way to keep a static variable is to declare it as a
parameter and give it a default value. The parameter list is evaluated
when the function is compiled, not when it is called. The underscores
are added as per convention to indicate that the variable is
special/private.

Example-

def cumulative_sum(arg, __static__ = []):
__static__.append(arg)
return reduce(lambda a,b: a + b, __static__)

#-------------------
cumulative_sum(1)1 cumulative_sum(1)2 cumulative_sum(1)

3

This default-value hack is what my presets decorator was motivated to replace
(if you are willing to depend to a byte-code-hacking decorator ;-)

Regards,
Bengt Richter
Jul 19 '05 #12

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: IHateSuperman | last post by:
public class StaticField2{ public static void main(String args){ private int x, y; // <<== error 1 for ( y = 0 ; y < 100 ; y++){ x = StaticMethod(); System.out.println(" x = "+x); } } public...
2
by: Steve | last post by:
Is a static method that uses local variables thread safe (eg in a web service) In the following code assuming GetRandomValue() and DoSomethingElse() are thread safe, is the static method thread...
9
by: Bryan Parkoff | last post by:
I have noticed that C programmers put static keyword beside global variable and global functions in C source codes. I believe that it is not necessary and it is not the practice in C++. Static...
3
by: Datta Patil | last post by:
Hi , #include<stdio.h> func(static int k) /* point2 : why this is not giving error */ { int i = 10 ; // static int j = &i ; /* point 1: this will give compile time error */ return k; } /*...
2
by: blue | last post by:
We have an abstract class with all static methods. It makes sense to have it static because there are no member variables and the constructor is empty. Some of the methods update the SQL Server...
3
by: David MacKay | last post by:
Dear Greater Py, <motivation note="reading this bit is optional"> I am writing a command-line reader for python. I'm trying to write something with the same brevity as perl's one-liner ...
4
by: Carl J. Van Arsdall | last post by:
It seems the more I come to learn about Python as a langauge and the way its used I've come across several discussions where people discuss how to do things using an OO model and then how to design...
55
by: Zytan | last post by:
I see that static is more restricted in C# than in C++. It appears usable only on classes and methods, and data members, but cannot be created within a method itself. Surely this is possible in...
16
by: RB | last post by:
Hi clever people :-) I've noticed a lot of people stating not to use static variables with ASP.NET, and, as I understand it, the reason is because the variable is shared across user sessions -...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.