bitwise operator, bits dont go into bitbucket..?

Chris Angelico rosuav at gmail.com
Tue Nov 10 18:16:17 EST 2015


On Wed, Nov 11, 2015 at 9:56 AM, kent nyberg <kent at z-sverige.nu> wrote:
> So, to check if 0b010[this one bit]010 is set,   i do   & 0b0001000
>
> That is,  I set just that one to 1 in the other and then the & operator will make it return
> 0 if its not set. Since every other is zero, the return will be zero if its not. Since & operator sets 0
> if not both are 1. Right?
>
> Id so, Thanks.

Exactly! It's common to have named constants for things that matter to
you; for example, you can find out if a file/directory is
world-writable like this:

>>> import stat
>>> os.stat("/").st_mode & stat.S_IWOTH
0
>>> os.stat("/tmp").st_mode & stat.S_IWOTH
2

So my root directory is not world writable (result of zero), and the
/tmp directory is. (This is not surprising.) The S_IWOTH constant is
simply the integer 2, but giving it a name makes it a bit easier to
see what's going on in the code. (Not that the name is abundantly
clear... it could be improved on. But it's better than just '2'.)

> My misunderstanding was that
> 0b01000   (for example,) first could be shifted left. To become 0b10000.
> And then shifted right to become 0b00001.
> The shifting would turn every other digit to 0 and leave only the wanted one untouched.
> That way, I could check if its 0 or 1.  If you understand my own logic of how it works.
> But I got it wrong,  and I think I know how to do it with & operator.

That's true of right shifting, but when you left shift, you're
depending on a specific word size. Even in C, it's possible to get
burned by that (eg when you move from 32-bit to 64-bit), and in
Python, integers have infinite size. If you definitely want that
behaviour, you can do this:

(0b01000 << 1) & 0b11111

which will mask off your result to just five bits, giving you the
"drop the top bit" effect. But for bit testing and manipulation, it's
way easier to use AND/OR/XOR than shifts.

The one place you might want to use bit shifts is in _creating_ those
constants. For instance:

STYLE_FOO = 1 << 0
STYLE_BAR = 1 << 1
STYLE_BAZ = 1 << 2
STYLE_ABC = 1 << 3
STYLE_QWE = 1 << 4
STYLE_XYZ = 1 << 5

>From this table, it's obvious that they've been assigned successive
bits. You can do the same with an enumeration:

>>> class Style(enum.IntEnum):
...     FOO = 1 << 0
...     BAR = 1 << 1
...     BAZ = 1 << 2
...     ABC = 1 << 3
...     QWE = 1 << 4
...     XYZ = 1 << 5
...
>>> Style.BAR
<Style.BAR: 2>
>>> Style.QWE
<Style.QWE: 16>

And then you can test to see if some style was chosen:

>>> widget = Style.FOO | Style.QWE
>>> widget & Style.ABC
0
>>> widget & Style.QWE
16

Does that make things a bit easier to read?

ChrisA



More information about the Python-list mailing list