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

Efficient Bit addressing in Python.

70 views
Skip to first unread message

Hendrik van Rooyen

unread,
Oct 9, 2008, 6:30:18 PM10/9/08
to pytho...@python.org

Is there a canonical way to address the bits in a structure
like an array or string or struct?

Or alternatively, is there a good way to combine eight
ints that represent bits into one of the bytes in some
array or string or whatever?

It seems to me that there is a dilemma here :

if you can write:

bit3 = 1

Then you have to jump through hoops to get
bit0 through bit7 into some byte that you can send
to an i/o routine.

On the other hand, if you keep the bits "in" the
byte, then you can write:

byte[3] = '\x7e'

but you have to jump through hoops to get at
the individual bits.

Is there a "best" way?

It would be nice to be able to write:

if io.byte2.bit3:
do_something()

if io.byte2 == alarm_value:
do_something_else()

where:

io.byte2 & 8 "is" io.byte2.bit3

Is this possible?

- Hendrik

Tino Wildenhain

unread,
Oct 9, 2008, 7:49:34 AM10/9/08
to Hendrik van Rooyen, pytho...@python.org
Hi,

byte1 byte2? this does not look very practical
to me. In the simplest form of storing
your values in a text string, you could just
use ord() to get the byte value and
operate on it with 1<<0 1<<1 1<<3 and so on.

If you want, put a module in which defines the
constants

bit1=1<<0
bit2=1<<1

and so on and use it via
if byte & bit1: ...

more efficiently for operations on really big
bit strings is probably just using integers.

HTH
Tino


> Is this possible?
>
> - Hendrik
>

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

Lie Ryan

unread,
Oct 9, 2008, 11:22:53 AM10/9/08
to pytho...@python.org
On Fri, 10 Oct 2008 00:30:18 +0200, Hendrik van Rooyen wrote:

> Is there a canonical way to address the bits in a structure like an
> array or string or struct?
>
> Or alternatively, is there a good way to combine eight ints that
> represent bits into one of the bytes in some array or string or
> whatever?
>
> It seems to me that there is a dilemma here :
>
> if you can write:
>
> bit3 = 1
>
> Then you have to jump through hoops to get bit0 through bit7 into some
> byte that you can send to an i/o routine.
>
> On the other hand, if you keep the bits "in" the byte, then you can
> write:
>
> byte[3] = '\x7e'
>
> but you have to jump through hoops to get at the individual bits.
>
> Is there a "best" way?
>
> It would be nice to be able to write:
>
> if io.byte2.bit3:
> do_something()
>
> if io.byte2 == alarm_value:
> do_something_else()
>
> where:
>
> io.byte2 & 8 "is" io.byte2.bit3
>

> Is this possible?
>
> - Hendrik

You'll find that in most cases, using integer or Boolean is enough. There
are some edge cases, which requires bit addressing for speed or memory
optimizations, in python, the usual response to that kind of optimization
requirement is to move that part of the code to C.

If, for the more usual case, you require the bit addressing because the
data structure is more convenient to work with that way, you could use a
class that implements the __getitem__, __setitem__, and a "join" method.

anyway, if you used str, it isn't hard to have both behavior (easy
indexing and easy joining) the bits:
>>> a = '01101010'
>>> a[0], a[1]
('0', '1')
>>> a
'01101010'
>>> int(a, 2)
106
>>> chr(int(a, 2))
'j'
>>> def bin2int(b): return int(a, 2)
...
>>> def bin2chr(b): return chr(int(a, 2))
...
>>>

George Sakkis

unread,
Oct 9, 2008, 11:53:45 AM10/9/08
to
On Oct 9, 6:30 pm, "Hendrik van Rooyen" <m...@microcorp.co.za> wrote:

> Is there a canonical way to address the bits in a structure
> like an array or string or struct?

I don't know of a canonical way (bit hacking is not really common in
Python) but pehaps BitPacket [1] comes close to what you're after.

George

[1] http://hacks-galore.org/aleix/BitPacket/

Mensanator

unread,
Oct 9, 2008, 2:16:09 PM10/9/08
to

I use the gmpy module for all my bit related work and
have been very satisfied with the results.

Examples of functions pertinent to bit operations:

digits(...)
digits(x[,base]): returns Python string representing x in the
given base (2 to 36, default 10 if omitted or 0); leading '-'
present if x<0, but no leading '+' if x>=0. x must be an mpz,
or else gets coerced into one.

getbit(...)
getbit(x,n): returns 0 or 1, the bit-value of bit n of x;
n must be an ordinary Python int, >=0; x is an mpz, or else
gets coerced to one.

hamdist(...)
hamdist(x,y): returns the Hamming distance (number of bit-
positions
where the bits differ) between x and y. x and y must be mpz,
or else
get coerced to mpz.

lowbits(...)
lowbits(x,n): returns the n lowest bits of x; n must be an
ordinary Python int, >0; x must be an mpz, or else gets
coerced to one.

numdigits(...)
numdigits(x[,base]): returns length of string representing x
in
the given base (2 to 36, default 10 if omitted or 0); the
value
returned may sometimes be 1 more than necessary; no provision
for any 'sign' characte, nor leading '0' or '0x' decoration,
is made in the returned length. x must be an mpz, or else
gets
coerced into one.

popcount(...)
popcount(x): returns the number of 1-bits set in x; note that
this is 'infinite' if x<0, and in that case, -1 is returned.
x must be an mpz, or else gets coerced to one.

scan0(...)
scan0(x, n=0): returns the bit-index of the first 0-bit of x
(that
is at least n); n must be an ordinary Python int, >=0. If no
more
0-bits are in x at or above bit-index n (which can only happen
for
x<0, notionally extended with infinite 1-bits), None is
returned.
x must be an mpz, or else gets coerced to one.

scan1(...)
scan1(x, n=0): returns the bit-index of the first 1-bit of x
(that
is at least n); n must be an ordinary Python int, >=0. If no
more
1-bits are in x at or above bit-index n (which can only happen
for
x>=0, notionally extended with infinite 0-bits), None is
returned.
x must be an mpz, or else gets coerced to one.

setbit(...)
setbit(x,n,v=1): returns a copy of the value of x, with bit n
set
to value v; n must be an ordinary Python int, >=0; v, 0 or !
=0;
x must be an mpz, or else gets coerced to one.

Hendrik van Rooyen

unread,
Oct 10, 2008, 3:41:45 PM10/10/08
to Tino Wildenhain, pytho...@python.org

"Tino Wildenhain" wrote:


>
> byte1 byte2? this does not look very practical
> to me. In the simplest form of storing
> your values in a text string, you could just
> use ord() to get the byte value and
> operate on it with 1<<0 1<<1 1<<3 and so on.
>
> If you want, put a module in which defines the
> constants
>
> bit1=1<<0
> bit2=1<<1
>
> and so on and use it via
> if byte & bit1: ...

This is what I meant by "jumping through hoops".

>
> more efficiently for operations on really big
> bit strings is probably just using integers.

Sure, one could for instance make a list of eight-entry lists:

io = [[b0,b1,b2,b3,b4,b5,b6,b7], ]

Then the hoop jumping goes in the opposite
direction - to get hold of an actual byte, you
have to rotate the bits into some byte one at a
time.
This approach has the advantage that you can
add a ninth "dirty" bit to indicate that the "byte"
in question needs to be written out.

Is there not some OO way of hiding this
bit banging complexity?

Using getters and setters? - I tend to go "tilt"
like a cheap slot machine when I read that stuff.

- Hendrik

--
Reality is the bane of the sane

Tino Wildenhain

unread,
Oct 10, 2008, 5:33:31 AM10/10/08
to Hendrik van Rooyen, pytho...@python.org
Hendrik van Rooyen wrote:
> "Tino Wildenhain" wrote:
>
>
>> byte1 byte2? this does not look very practical
>> to me. In the simplest form of storing
>> your values in a text string, you could just
>> use ord() to get the byte value and
>> operate on it with 1<<0 1<<1 1<<3 and so on.
>>
>> If you want, put a module in which defines the
>> constants
>>
>> bit1=1<<0
>> bit2=1<<1
>>
>> and so on and use it via
>> if byte & bit1: ...
>
> This is what I meant by "jumping through hoops".
>
>> more efficiently for operations on really big
>> bit strings is probably just using integers.
>
> Sure, one could for instance make a list of eight-entry lists:
>
> io = [[b0,b1,b2,b3,b4,b5,b6,b7], ]

what should that represent? Which byte order
do you have in mind etc?


>
> Then the hoop jumping goes in the opposite
> direction - to get hold of an actual byte, you
> have to rotate the bits into some byte one at a
> time.

Well, thats one would expect by your proposed interface.

Can you perhaps outline what kind of application
you have in mind and which operations look meaningfull
to that?

I'm familar with embedded hardware where you would have
a couple of registers where you usually only have
the distinction between 8-bit or 16 bit flag registers
where it makes sense to individually influence bits.
Personally I can't follow you on the path to have
arbitrary lengthy bitfields - even nore to
have artifically attributes (like bit5) on them.

Just using a big integer to represent your bitfield
and using binary operators on it does not sound
so wrong to me in this case.

Of course one could create a type which derives
from sequence types and implement something
like

bitfieldinstance[bitindex] (where 0 is LSB)

would you like fries... err slices with that?

e.g.

>>> bf=BitField(10)
>>> int(bf[1:])
5

?

> This approach has the advantage that you can
> add a ninth "dirty" bit to indicate that the "byte"
> in question needs to be written out.

What do you mean by "written out" to where?

> Is there not some OO way of hiding this
> bit banging complexity?

foo & bar is complex? So you want to replace foo + bar
as well with something? ;)

> Using getters and setters? - I tend to go "tilt"
> like a cheap slot machine when I read that stuff.

Getters setters? Where would that improve the situation
beside having to write lots of unneccessary code?

Regards
Tino


Ross Ridge

unread,
Oct 10, 2008, 5:57:46 AM10/10/08
to
Hendrik van Rooyen <ma...@microcorp.co.za> wrote:
>Is there a canonical way to address the bits in a structure
>like an array or string or struct?
>
>Or alternatively, is there a good way to combine eight
>ints that represent bits into one of the bytes in some
>array or string or whatever?

This is the code I use to convert large bit arrays to byte strings and
back:

import string
import binascii
import array

_tr_16 = string.maketrans("0123456789abcdef",
"\x00\x01\x02\x03"
"\x10\x11\x12\x13"
"\x20\x21\x22\x23"
"\x30\x31\x32\x33")
_tr_4 = string.maketrans("0123",
"\x00\x01"
"\x10\x11")
_tr_2 = string.maketrans("01", "\x00\x01")

def string_to_bit_array(s):
"""Convert a string to an array containing a sequence of bits."""
s = binascii.hexlify(s).translate(_tr_16)
s = binascii.hexlify(s).translate(_tr_4)
s = binascii.hexlify(s).translate(_tr_2)
a = array.array('B', s)
return a

_tr_rev_2 = string.maketrans("\x00\x01", "01")
_tr_rev_4 = string.maketrans("\x00\x01"
"\x10\x11",
"0123")
_tr_rev_16 = string.maketrans("\x00\x01\x02\x03"
"\x10\x11\x12\x13"
"\x20\x21\x22\x23"
"\x30\x31\x32\x33",
"0123456789abcdef")
def bit_array_to_string(a):
"""Convert an array containing a sequence of bits to a string."""
remainder = len(a) % 8
if remainder != 0:
a.fromlist([0] * (8 - remainder))
s = a.tostring()
s = binascii.unhexlify(s.translate(_tr_rev_2))
s = binascii.unhexlify(s.translate(_tr_rev_4))
return binascii.unhexlify(s.translate(_tr_rev_16))

I don't think you can do anything faster with standard modules, although
it might not be effecient if you're only working with a single byte.

Ross Ridge

--
l/ // Ross Ridge -- The Great HTMU
[oo][oo] rri...@csclub.uwaterloo.ca
-()-/()/ http://www.csclub.uwaterloo.ca/~rridge/
db //

Hendrik van Rooyen

unread,
Oct 10, 2008, 5:32:16 PM10/10/08
to pytho...@python.org
George Sakkis wrote:

>I don't know of a canonical way (bit hacking is not really common in
>Python) but pehaps BitPacket [1] comes close to what you're after.
>
>George
>
>[1] http://hacks-galore.org/aleix/BitPacket/

Thanks for the link - I will check it out

- Hendrik

Hendrik van Rooyen

unread,
Oct 10, 2008, 5:34:02 PM10/10/08
to pytho...@python.org

Mensanator wrote:

>I use the gmpy module for all my bit related work and
>have been very satisfied with the results.

8<----------- gmpy function list -------------------

Thanks. All of this looks good. Will check out
gmpy too.

- Hendrik

Hendrik van Rooyen

unread,
Oct 10, 2008, 5:29:19 PM10/10/08
to pytho...@python.org
Lie Ryan wrote:


>You'll find that in most cases, using integer or Boolean is enough. There
>are some edge cases, which requires bit addressing for speed or memory
>optimizations, in python, the usual response to that kind of optimization
>requirement is to move that part of the code to C.
>
>If, for the more usual case, you require the bit addressing because the
>data structure is more convenient to work with that way, you could use a
>class that implements the __getitem__, __setitem__, and a "join" method.

I had a vague feeling that this was the way to go,(see
my reply to Tino) but I have been resisting, kicking
and screaming, to get deeply involved in OO - Using
Tkinter is enough OO for my microprocessor biased
taste.

>anyway, if you used str, it isn't hard to have both behavior (easy
>indexing and easy joining) the bits:
>

>>>> a =3D '01101010'


>>>> a[0], a[1]
>('0', '1')
>>>> a
>'01101010'
>>>> int(a, 2)
>106
>>>> chr(int(a, 2))
>'j'
>>>> def bin2int(b): return int(a, 2)
...
>>>> def bin2chr(b): return chr(int(a, 2))

Thanks. This is the best I have seen up to now.

I was stuck because I was insisting on
storing real bits in real strings, eight
bits per byte, instead of storing ascii bits
and remembering about int(x,2).

In fact I keep forgetting about the
second argument of int...

I could go with a list like this:

inputs = [['10001000',''],['11110000',''],['01010101','']]

Where the second entry in the list is a "changed" bit.

Outputs are a bit more of a hassle - strings are immutable,
so I can't write:

input[1][0][3]='1'

but that is easily fixed by using array.array.

Thanks for the response

- Hendrik

Hendrik van Rooyen

unread,
Oct 10, 2008, 6:27:44 PM10/10/08
to Tino Wildenhain, pytho...@python.org
"Tino Wildenhain" wrote:

> Hendrik van Rooyen wrote:
> > "Tino Wildenhain" wrote:

8<----------------------------


> > Sure, one could for instance make a list of eight-entry lists:
> >
> > io = [[b0,b1,b2,b3,b4,b5,b6,b7], ]
>
> what should that represent? Which byte order
> do you have in mind etc?

Each list of bits in the io list would represent bits from least to most
significant, and would have to be collected into one byte before
being output to the hardware in the case of outputs, and would
have their source in one of the bytes read from the hardware, being
scattered from the input byte to the individual bits

8<----------------------------------------------


>
> Can you perhaps outline what kind of application
> you have in mind and which operations look meaningfull
> to that?

I am working on a controller for a small machine - I am using
the GPIO port on an eBox to form a slow bus that addresses
latches and buffers on external boards via a ribbon cable.
The idea is that the ebox and the io boards would clip on a
DIN rail and form a PAC (Programmable Automation Controller)

Each external board has either 8 inputs, or 8 outputs, and the
addressing scheme allows eight such pairs of boards, so that the
complete io structure could be represented in 16 bytes - eight
for the inputs, and eight for the outputs, giving 2 arrays of 64 bits,
if I use a real bit to represent the state of the voltage on the wire.

>
> I'm familar with embedded hardware where you would have
> a couple of registers where you usually only have
> the distinction between 8-bit or 16 bit flag registers
> where it makes sense to individually influence bits.
> Personally I can't follow you on the path to have
> arbitrary lengthy bitfields - even nore to
> have artifically attributes (like bit5) on them.
>

something like bit5 represents a name for the input or
output in question - in practice, it would have a name
like "e_stop" for an emergency stop input, or "push"
for an actuator that pushes something.

> Just using a big integer to represent your bitfield
> and using binary operators on it does not sound
> so wrong to me in this case.
>
> Of course one could create a type which derives
> from sequence types and implement something
> like
>
> bitfieldinstance[bitindex] (where 0 is LSB)
>
> would you like fries... err slices with that?
>
> e.g.
>
> >>> bf=BitField(10)
> >>> int(bf[1:])
> 5

If I can just address the thing by name I would be happy:

if e_stop:
put_everything_off ()

and a simple sequence:

push = 1 # actuates the pneumatic pusher

while not push_forward: # waits for it to arrive
time.sleep(0.001)

push = 0 # reverses the motion again.

This of course means that there has to be another
thread active to actually do the i/o on a periodic basis,
gathering the outputs and writing them out, and reading
the inputs and scattering them to the various named input
bits

I would even not mind if I have to write:

if e_stop():
put_everything_off()

or:

set(push,1)

>
> > This approach has the advantage that you can
> > add a ninth "dirty" bit to indicate that the "byte"
> > in question needs to be written out.
>
> What do you mean by "written out" to where?
>

See above explanation - see also a recent thread here
about "Python string immutability broken" where I posted the
prototype ctypes code, if you are really interested...

> > Is there not some OO way of hiding this
> > bit banging complexity?
>
> foo & bar is complex? So you want to replace foo + bar
> as well with something? ;)
>
> > Using getters and setters? - I tend to go "tilt"
> > like a cheap slot machine when I read that stuff.
>
> Getters setters? Where would that improve the situation
> beside having to write lots of unneccessary code?
>

Not necessarily unnecessary - the getters and setters could be
used to actually do the i/o to the relevant card when anything
makes an access to one of the bits on the memory representation
of that card - that would obviate the necessity for a second thread...

- Hendrik


Lie

unread,
Oct 10, 2008, 1:54:47 PM10/10/08
to
On Oct 11, 5:27 am, "Hendrik van Rooyen" <m...@microcorp.co.za> wrote:
> This of course means that there has to be another
> thread active to actually do the i/o on a periodic basis,
> gathering the outputs and writing them out, and reading
> the inputs and scattering them to the various named input
> bits

Not necessarily. You've mentioned two ways.

> I would even not mind if I have to write:
>
> if e_stop():
>     put_everything_off()
>
> or:
>
> set(push,1)
>

PS: Umm, a little bit off note: set is a built-in name, I'm a little
confused whether you meant on creating a "set" or setting the push bit
to 1, if the latter case it might be better to use set and clear
instead of passing a second parameter (and also to choose another
name).

Alternatively, there is one more way:
if bb.e_stop:
bb.e_stop = 0
where bb is some kind of "property bag" and .e_stop is a "property"
instead of an "instance member".

> > > This approach has the advantage that you can
> > > add a ninth "dirty" bit to indicate that the "byte"
> > > in question needs to be written out.
>
> > What do you mean by "written out" to where?
>
> See above explanation - see also a recent thread here
> about "Python string immutability broken" where I posted the
> prototype ctypes code, if you are really interested...
>
> > > Is there not some OO way of hiding this
> > > bit banging complexity?
>
> > foo & bar is complex? So you want to replace foo + bar
> > as well with something? ;)
>
> > > Using getters and setters? - I tend to go "tilt"
> > > like a cheap slot machine when I read that stuff.
>
> > Getters setters? Where would that improve the situation
> > beside having to write lots of unneccessary code?
>
> Not necessarily unnecessary - the getters and setters could be
> used to actually do the i/o to the relevant card when anything
> makes an access to one of the bits on the memory representation
> of that card - that would obviate the necessity for a second thread...

Rather than directly using getters and setters, I'd go with property.
It (usually) makes a cleaner external interface of the class. And for
the mess of having to write lots of boilerplate codes, you _could_
dynamically generate the boilerplate code from a dictionary (of name
to bit position) and currying (or something to that effect).
Alternatively, you could also do some magic with getattr and setattr.

Lie

unread,
Oct 10, 2008, 2:12:23 PM10/10/08
to
On Oct 11, 5:27 am, "Hendrik van Rooyen" <m...@microcorp.co.za> wrote:
> This of course means that there has to be another
> thread active to actually do the i/o on a periodic basis,
> gathering the outputs and writing them out, and reading
> the inputs and scattering them to the various named input
> bits

Not necessarily. You've mentioned two ways.

> I would even not mind if I have to write:


>
> if e_stop():
>     put_everything_off()
>
> or:
>
> set(push,1)
>

PS: Umm, a little bit off note: set is a built-in name, I'm a little


confused whether you meant on creating a "set" or setting the push bit
to 1, if the latter case it might be better to use set and clear
instead of passing a second parameter (and also to choose another
name).

Alternatively, there is one more way:
if bb.e_stop:
bb.e_stop = 0
where bb is some kind of "property bag" and .e_stop is a "property"
instead of an "instance member".

> > > This approach has the advantage that you can


> > > add a ninth "dirty" bit to indicate that the "byte"
> > > in question needs to be written out.
>
> > What do you mean by "written out" to where?
>
> See above explanation - see also a recent thread here
> about "Python string immutability broken" where I posted the
> prototype ctypes code, if you are really interested...
>
> > > Is there not some OO way of hiding this
> > > bit banging complexity?
>
> > foo & bar is complex? So you want to replace foo + bar
> > as well with something? ;)
>
> > > Using getters and setters? - I tend to go "tilt"
> > > like a cheap slot machine when I read that stuff.
>
> > Getters setters? Where would that improve the situation
> > beside having to write lots of unneccessary code?
>
> Not necessarily unnecessary - the getters and setters could be
> used to actually do the i/o to the relevant card when anything
> makes an access to one of the bits on the memory representation
> of that card - that would obviate the necessity for a second thread...

Rather than directly using getters and setters, I'd go with property.

Aaron "Castironpi" Brady

unread,
Oct 10, 2008, 11:37:58 PM10/10/08
to

This is tolerable. If you've got a better 'clear' operation than
'xor', you're welcome to it.

class BitSet:
def __init__( self, value ):
self.value= value
def __setitem__( self, index, value ):
if value:
self.value= self.value| (1<< index)
elif self[ index ]:
self.value= self.value^ (1<< index)
def __getitem__( self, index ):
return self.value& (1<< index )
def __repr__( self ):
return repr( self.value )

if __name__== '__main__':
b= BitSet( 15 )
print b
b[0]= 0
print b
b[0]= 1
print b
b[4]= 1
print b
b[4]= 0
print b

/Output:
15
14
15
31
15

Aaron "Castironpi" Brady

unread,
Oct 10, 2008, 11:41:08 PM10/10/08
to
On Oct 10, 10:37 pm, "Aaron \"Castironpi\" Brady"

<castiro...@gmail.com> wrote:
> On Oct 9, 5:30 pm, "Hendrik van Rooyen" <m...@microcorp.co.za> wrote:
>
>
>
> > Is there a canonical way to address the bits in a structure
> > like an array or string or struct?
>
> > Or alternatively, is there a good way to combine eight
> > ints that represent bits into one of the bytes in some
> > array or string or whatever?
snip

>
> class BitSet:
>     def __init__( self, value ):
>         self.value= value
>     def __setitem__( self, index, value ):
>         if value:
>             self.value= self.value| (1<< index)
>         elif self[ index ]:
>             self.value= self.value^ (1<< index)
>     def __getitem__( self, index ):
>         return self.value& (1<< index )
snip

This could read:

def __getitem__( self, index ):

return 1 if self.value& (1<< index ) else 0

Or you could shift self.value, and mask with unity.

Hendrik van Rooyen

unread,
Oct 11, 2008, 11:58:47 PM10/11/08
to pytho...@python.org
"Aaron \"Castironpi\" Brady" wrote:

>This is tolerable. Â If you've got a better 'clear' operation than


>'xor', you're welcome to it.

*grin* xor is a toggle bit fuction, and I did not like the recursive
call in your code. so here is a module bsed on your BitSet:
(I hope my tabs survive the journey)


"""
Module with input and output int bit addressable classes.

Loosely based on Castironpi's BitSet code

"""

class inbits(object):
"""
This is a 32 bit int of more or less addressable bits.
"""

def __init__ (self, value = 0,*args ):
"""This constructs the int that keeps the bits,
and makes a getbit function for each named bit from *args,
so that we can retreive them by instance.bitname(),
as well as by bool = instance[index_position]
"""

self.value = value
self.high_values = int('ffffffff',16)
for i,name in enumerate(args):
def __getbit__(idx = i):
# Real i/o code has to be added here to read the right byte
return self.__getitem__(idx)
self.__dict__[name] = __getbit__

def __setitem__( self, index, value ):

"""Here we can set a bit based on its position."""

if value:
self.value |= (1 << index)
else:
self.value &= self.high_values ^ (1 << index)

def __getitem__( self, index ):

"""This retreives a bit based on its position."""

return 1 if self.value & (1<< index ) else 0

def __repr__( self ):
return repr( self.value )

class outbits(object):
"""
This is a 32 bit int of more or less addressable bits.
"""

def __init__ (self, value = 0,*args ):
"""This constructs the int that keeps the bits,
and makes a setbit function for each named bit from *args,
so that we can set them by instance.bitname(bool),
as well as by instance[index_position] = bool
"""

self.value = value
self.high_values = int('ffffffff',16)
for i,name in enumerate(args):
def __setbit__(value,idx = i):
self.__setitem__(idx,value)
# Real i/o code has to be added here to write the right byte out
self.__dict__[name] = __setbit__

def __setitem__( self, index, value ):

"""Here we can set a bit based on its position."""

if value:
self.value |= (1 << index)
else:
self.value &= self.high_values ^ (1 << index)

def __getitem__( self, index ):

"""This retreives a bit based on its position."""

return 1 if self.value & (1<< index ) else 0

def __repr__( self ):
return repr( self.value )

if __name__== '__main__':

ins = inbits(0,'b0','b1','b2','b3','b4','b5','b6','b7')
outs = outbits(0,'b0','b1','b2','b3','b4','b5','b6','b7')
ins[3] = 1
outs.b4(1)
print 'ins now',ins,'outs now',outs,'outs[4] is',outs[4],'ins.b3() is',ins.b3()


Comments are welcome...

- Hendrik


Hendrik van Rooyen

unread,
Oct 11, 2008, 11:41:31 PM10/11/08
to pytho...@python.org
Ross Ridge wrote:

>This is the code I use to convert large bit arrays to byte strings and
>back:
>
>import string
>import binascii
>import array

8<--------------- examples ----------------------

>I don't think you can do anything faster with standard modules, although

>it might not be efficient if you're only working with a single byte.

Thanks I was not aware of binascii module this looks powerful.

- Hendrik

Hendrik van Rooyen

unread,
Oct 11, 2008, 11:50:40 PM10/11/08
to pytho...@python.org
Lie <Li...mail.com> wrote:

>> This of course means that there has to be another
>> thread active to actually do the i/o on a periodic basis,
>> gathering the outputs and writing them out, and reading
>> the inputs and scattering them to the various named input
>> bits
>
>Not necessarily. You've mentioned two ways.

True.

>> I would even not mind if I have to write:
>>
>> if e_stop():
>> put_everything_off()
>>
>> or:
>>
>> set(push,1)
>>
>
>PS: Umm, a little bit off note: set is a built-in name, I'm a little
>confused whether you meant on creating a "set" or setting the push bit
>to 1, if the latter case it might be better to use set and clear
>instead of passing a second parameter (and also to choose another
>name).
>

True. this was a brain fart - should have been setbit or something.

>.Alternatively, there is one more way:


>if bb.e_stop:
> bb.e_stop = 0
>where bb is some kind of "property bag" and .e_stop is a "property"
>instead of an "instance member".
>

what is the advantage?

8<-----------------------------

>Rather than directly using getters and setters, I'd go with property.
>It (usually) makes a cleaner external interface of the class. And for
>the mess of having to write lots of boilerplate codes, you _could_
>dynamically generate the boilerplate code from a dictionary (of name
>to bit position) and currying (or something to that effect).
>Alternatively, you could also do some magic with getattr and setattr.

I am not too sure I know how...

- Hendrik

Ross Ridge

unread,
Oct 11, 2008, 10:20:35 PM10/11/08
to
Ross Ridge wrote:
>I don't think you can do anything faster with standard modules, although
>it might not be efficient if you're only working with a single byte.

Hendrik van Rooyen <ma...@microcorp.co.za> wrote:
>Thanks I was not aware of binascii module this looks powerful.

Not really. It's just used as part of a trick to quickly convert a byte
string in to a bit string (a byte string with just 0s and 1s).

Unfortunately fromr you other posts you do seem to be working on
a single byte a time, so my technique probably won't be efficient.
You probably want just want to be using constants and bit masking.
Something like:


PAC_EMERGENCY_STOP = 0x01 # bit #0 on output port 0
PAC_OUTPUT_0_1 = 0x02 # replace with names for other functions
PAC_OUTPUT_0_2 = 0x04
PAC_PNEUMATIC_PUSHER = 0x08 # bit #3 on output port 0
...

def gpio_bit_on(port, bit):
r = gpio_in(port)
r |= bit
r = gpio_out(port)

def gpio_bit_off(port, bit):
r = gpio_in(port)
r &= ~bit
r = gpio_out(port)

class pac(object):
def everything_off(self):
gpio_out(PAC_OUTPUT_PORT_0, 0)
gpio_out(PAC_OUTPUT_PORT_1, 0)
gpio_out(PAC_OUTPUT_PORT_2, 0)
...
gpio_out(PAC_OUTPUT_PORT_7, 0)

def emergency_stop(self):
gpio_bit_on(PAC_OUTPUT_PORT_0, PAC_EMERGENCY_STOP)

def pusher_on(self):
gpio_bit_on(PAC_OUTPUT_PORT_0, PAC_PNEUMATIC_PUSHER)

def pusher_off(self):
gpio_bit_off(PAC_OUTPUT_PORT_0, PAC_PNEUMATIC_PUSHER)


Bit twiddling like this is pretty basic.

Hendrik van Rooyen

unread,
Oct 12, 2008, 4:19:25 PM10/12/08
to pytho...@python.org

Ross Ridge <rrid...lub.uwaterloo.ca> wrote:

>Unfortunately from your other posts you do seem to be working on


>a single byte a time, so my technique probably won't be efficient.

Its a bit more - the hardware allows for 64 lines in and 64 lines out.

>You probably want just want to be using constants and bit masking.
>Something like:

8< ------------- standard and and or examples ----------------

This is approximately how I was doing it before I started the thread,
but I was unsatisfied, and started looking for a way to directly
address the bits, more as a further exploration of Python.

>Bit twiddling like this is pretty basic.

Yes it is, and in what we do it is also pervasive,
and I miss my 8051/8031 assembler instructions
where I can do an atomic "jump if bit set then clear' on
a named bit in the bit addressable space, as well as
a direct set or clear of a named bit, without resorting
to anding and oring of bytes.

Now I know that I can never do the jump in python, but
I had hoped that I could get close to the direct set
and clear, and the thread has been useful in that it
has rubbed my nose into a lot of corners where I would
otherwise never have gone. (like the gmpy stuff, for
instance, and mucking around with bitfield-like classes,
and the binascii stuff.)

And I now _almost_ have my direct bit addressability...

However - Python has failed to show me "the one and
only one obvious way".

*grins and ducks*

Thanks to all who responded.

- Hendrik


0 new messages