For example, suppose I have:
def set_bit (bit_index, bit_value):
static bits = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
bits [bit_index] = bit_value
print "\tBit Array:"
int i
while (i < len(bits):
print bits[i],
print '\n'
I realize this can be implemented by making bits global, but can
this be done by making it private only internal to set_bit()? I don't
want bits to be reinitialized each time. It must retain the set values
for the next time it is called.
Thanks in advance:
Michael Yanowitz
You could do it by defining static_bits as a keyword parameter with a
default value:
>>> def set_bit(bit_index, bit_value, static_bits=[0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0]):
static_bits[bit_index] = bit_value
return static_bits
>>> set_bit(2, 1)
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
>>> set_bit(3, 1)
[0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
>>> set_bit(2, 0)
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
It might be a better idea to use a class for this though:
>>> class Bits(object):
def __init__(self):
self.bits = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
def set(self, index, value):
self.bits[index] = value
return self.bits
>>> bits = Bits()
>>> bits.set(2, 1)
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
>>> bits.set(3, 1)
[0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
>>> bits.set(2, 0)
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
When using a class, you can have different lists of bits independently
of each other in a program. And you can define other operations on the
bits: you could for example create methods to set or clear all bits at
once. With your approach, set_bit is the only function that has access
to the bits so you can't easily create other operations.
--
If I have been able to see further, it was only because I stood
on the shoulders of giants. -- Isaac Newton
Roel Schroeven
If you declare bits in set_bit() as "global bits = ...", it will create
it as a global variable without you having to declare it outside of the
function. Just be careful about name conflicts.
Are you sure?
def fun():
global x = 10
fun()
print x
Bye,
bearophile
This works for me:
>>> def fun():
global x
x = 10
>>> fun()
>>> print x
10
>>>
But of course:
>>> def fun():
global x = 10
SyntaxError: invalid syntax
>>>
Python does not have static variables in the sense that C does. You can
fake it in various ways, though. If I had to do it, I'd define a
callable object instead of a function, along the lines of this:
class BitSetter(object):
def __init__(self):
self.bits = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
def __call__(self, bit_index, bit_value):
self.bits[bit_index] = bit_value
# do something with self.bits here...
print self.bits
set_bit = BitSetter()
Now you can call set_bit(...) as if it were a function, and it'll behave
the way you want.
Hope this helps,
Carsten.
Last solution being to use a closure:
def make_bits():
bits = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
def set_bit(bit_index, bit_value):
bits[bit_index] = bit_values
def get_bits():
# returns a copy so we don't overwrite
return bits[:]
return set_bit, get_bits
set_bit, get_bits = make_bits()
But the better solution is probably to make it a class.
Many people suggest that using a class for this is the Python idiom (and
perhaps it is), but I prefer to use a decorator for adding attributes to
functions in this case:
def attrs ( **kwds ):
''' taken from PEP 318 '''
def decorate ( f ):
for k in kwds:
setattr ( f, k, kwds [ k ] )
return f
return decorate
@attrs ( bits = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] )
def set_bit ( idx, val ):
set_bit.bits [ idx ] = int ( bool ( val ) )
print "Bit Array:"
for i in set_bit.bits:
print i,
print
>>> set_bit ( 4, 1 )
Bit Array:
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
>>> set_bit ( 5, 1 )
Bit Array:
0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0
Regards,
Cliff
Syntax error
> while (i < len(bits):
> print bits[i],
Nice infinite loop...
Python's canonical way to iterate over a sequence is the for loop:
for bit in bits:
print bit,
And FWIW, for what you want to do, you don't even need a loop:
print "\n".join(map(str, bits))
> print '\n'
>
> I realize this can be implemented by making bits global, but can
> this be done by making it private only internal to set_bit()? I don't
> want bits to be reinitialized each time. It must retain the set values
> for the next time it is called.
While there are some more or less hackish solutions (cf Roel answers and
my answers to it), the usual way to have functions maintaining state is
to define a class and instanciate it. Note that Python's functions are
objects, and that it's possible to write your own callable objects too
if you really want a function call syntax:
class Setbit(object):
def __init__(self):
self._bits = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
def call(self, index, value):
self._bits[index] = value
def values(self):
return self._bits[:]
set_bit = Setbit()
set_bit(1, 1)
print "".join(map(str, set_bit.values()))
> @attrs ( bits = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] )
Also, IMO, it's a bit more readable to write:
bits = [ 0 for i in range ( 16 ) ]
which avoids the necessity of counting the zeros to know how many there
are.
Regards,
Cliff
--
Or even:
bits = [ 0 ] * 16
Just be careful to only use that style when the contents of the array
are non-mutable. The list comp does the right thing in that case (at
risk of going on a tangent):
Right:
>>> bits = [ { } for i in range ( 16 ) ]
>>> bits
[{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}]
>>> bits [ 0 ][ 'a' ] = 1
>>> bits
[{'a': 1}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}]
Wrong:
>>> bits = [ {} ] * 16
>>> bits [ 0 ][ 'a' ] = 1
>>> bits
[{'a': 1}, {'a': 1}, {'a': 1}, {'a': 1}, {'a': 1}, {'a': 1}, {'a': 1},
{'a': 1}, {'a': 1}, {'a': 1}, {'a': 1}, {'a': 1}, {'a': 1}, {'a': 1},
{'a': 1}, {'a': 1}]
>>>
Regards,
Cliff
BTW, I'm assuming this example was contrived. In real life, I wonder
why you'd ever want to use anything besides:
bits = [ 0 ] * 16
bits [ 4 ] = 1
print "Bit Array:"
print ' '.join ( bits )
Having a "set_bit" function seems redundant when the language syntax
directly supports what you are trying to do.
Regards,
Cliff
--
You can do things with function attributes
def foo(x):
foo.static += x
return foo.static
foo.static = 0
If you are going to set function attributes a lot, then you might like
to addd an attriute setter decorator to your toolbox:
def attributeSetter( **kw):
" decorator creator: initialises function attributes"
def func2(func):
" decorator: initialises function attributes"
func.__dict__.update(kw)
return func
return func2
def accumulator(n):
""" return an accumulator function that starts at n
>>> x3 = accumulator(3)
>>> x3.acc
3
>>> x3(4)
7
>>> x3.acc
7
"""
@attributeSetter(acc = n)
def accum(i):
accum.acc+= i
return accum.acc
return accum
- Paddy
global x
x = 10
Close enough ^^;
-----Original Message-----
From: Cliff Wells [mailto:cl...@develix.com]
Sent: Monday, July 31, 2006 4:55 PM
To: Michael Yanowitz
Cc: pytho...@python.org
Subject: Re: Static Variables in Python?
On Mon, 2006-07-31 at 15:21 -0400, Michael Yanowitz wrote:
> Is it possible to have a static variable in Python -
> a local variable in a function that retains its value.
>
> For example, suppose I have:
>
> def set_bit (bit_index, bit_value):
> static bits = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
> bits [bit_index] = bit_value
>
> print "\tBit Array:"
> int i
> while (i < len(bits):
> print bits[i],
> print '\n'
>
>
> I realize this can be implemented by making bits global, but can
> this be done by making it private only internal to set_bit()? I don't
> want bits to be reinitialized each time. It must retain the set values
> for the next time it is called.
BTW, I'm assuming this example was contrived. In real life, I wonder
why you'd ever want to use anything besides:
bits = [ 0 ] * 16
bits [ 4 ] = 1
print "Bit Array:"
print ' '.join ( bits )
Having a "set_bit" function seems redundant when the language syntax
directly supports what you are trying to do.
Regards,
Cliff
--
Thanks everyone for your help. Yes I know it is contrived. Well it is
as over-simplified version of what I really want. And yes, I do realize
after sending it about the infinite loop in the printing. I tried too
quickly to come up with a good example without testing it first.
I like the class idea, however I realize that the class object itself
has to be global. I will look into the decorators - something which I have
avoided until now.
I tried creating a class, but got an error:
# ********* class BitsClass *****************************************
class BitsClass (object):
def __init__(self, num_bits):
self.bits=[]
for i in range(num_bits):
self.bits.append(0)
def set(self, bit_index, value):
self.bits[bit_index] = value
return self.bits
def get(self, bit_index):
if ((bit_index >= 0) and (bit_index < len(self.bits))):
return self.bits[bit_index]
else:
return scenario_globals.ERROR_
def display(self):
i = 0
while (i < len(self.bits)):
print self.bits[i],
i += 1
print '\n',
global the_bits
the_bits = BitsClass(16)
# inside another function I have:
global the_bits
the_bits.set(index, value)
but I get back:
Traceback (most recent call last):
...
File "scenario_sync.py", line 245, in get_discrete_data
the_bits.set(index, value)
AttributeError: 'DiscreteBits' object has no attribute 'set'
There is
I was also disappointed, I was hoping I could use BitsClass.print()
instead of BitsClass.display().
>>> class BitsClass (object):
... def __init__(self, num_bits):
... self.bits=[]
... for i in range(num_bits):
... self.bits.append(0)
... def set(self, bit_index, value):
... self.bits[bit_index] = value
... return self.bits
... def get(self, bit_index):
... if ((bit_index >= 0) and (bit_index < len(self.bits))):
... return self.bits[bit_index]
... else:
... return scenario_globals.ERROR_
... def display(self):
... i = 0
... while (i < len(self.bits)):
... print self.bits[i],
... i += 1
... print '\n',
...
>>> the_bits = BitsClass(16)
>>> the_bits.set (4, 1)
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Works for me. I'm not sure what 'DiscreteBits' in your error refers to.
Also, you don't need to explicitly declare global variables "global".
Regards,
Cliff
--
#> I like the class idea, however I realize that the class object itself
#> has to be global.
But no more global than your original set_bit was...
--
Best wishes,
Slawomir Nowaczyk
( Slawomir...@cs.lth.se )
To err is human, but to really fuck things up takes a computer.
def accumulator(x):
# On first execution, the attribute is not yet known.
# This technique allows use of accumulator() as a
# function without the "consumer" having to initialize
# it.
if not "static" in dir(accumulator):
accumulator.static = 0
accumulator.static += x
return accumulator.static
print accumulator(3)
print accumulator(5)
Thanks Cameron, I'll accumulate this in my toolbox.
- pad.