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. 11 4898
> 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
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
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
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.
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
"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
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
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
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
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
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 This discussion thread is closed Replies have been disabled for this discussion. Similar topics
3 posts
views
Thread by IHateSuperman |
last post: by
|
2 posts
views
Thread by Steve |
last post: by
|
9 posts
views
Thread by Bryan Parkoff |
last post: by
|
3 posts
views
Thread by Datta Patil |
last post: by
|
2 posts
views
Thread by blue |
last post: by
|
3 posts
views
Thread by David MacKay |
last post: by
|
4 posts
views
Thread by Carl J. Van Arsdall |
last post: by
|
55 posts
views
Thread by Zytan |
last post: by
|
16 posts
views
Thread by RB |
last post: by
| | | | | | | | | | |