[Tutor] [spoiler] Re: Shifting arrays as though they are a 'word'

Peter Otten __peter__ at web.de
Tue Oct 9 03:27:15 EDT 2018


Chip Wachob wrote:

> All,
> 
> Sorry for not being more clear.  I think I was nearing my fill of
> Python for the day when I wrote.
> 
> Now, refreshed, let me see if I can fill in the blanks a bit more.

You have posted code sprinkled with prints and irrelevant details.
Please rewrite the relevant part into a simple function, 

def bitshift_right(data, nshift):
   ...

just the pure algorithm without any prints. Then find input data that
produces an AssertionError in the snippet below:

input = ...
rshift = ...
wanted_output = ...
assert bitshift_right(input, rshift) == wanted_output

I'm sure then someone is able and willing to point out the error in your 
implementation.

In the mean time here's my effort which also provides an idea on how to wrap 
the shifting into a simple class:

$ cat bitshift_oo.py       
format_bits = "{:08b}".format
try:
    format_bits(42)
except ValueError:
    # python 2
    def format_bits(b):
        return bin(b)[2:].zfill(8)


def to_bits(s, sep=""):
    return sep.join(map(format_bits, s))


def bitshift_right(b, n):
    nbytes, nbits = divmod(n, 8)
    length = len(b)
    if nbits:
        nbits = 8 - nbits
        a = [0]
        for bb in reversed(b):
            hi, lo = divmod(bb << nbits, 256)
            a[-1] |= lo
            a.append(hi)
        b = bytearray(a[::-1])
    return (bytearray(nbytes) + b)[:length]


class Bytes(bytearray):
    def __rshift__(self, n):
        return Bytes(bitshift_right(self, n))

    def __str__(self):
        return to_bits(self, " ")


if __name__ == "__main__":
    SAMPLE = Bytes(b"\xaa\xbb")
    for i in range(12):
        print(SAMPLE >> i)
$ python bitshift_oo.py
10101010 10111011
01010101 01011101
00101010 10101110
00010101 01010111
00001010 10101011
00000101 01010101
00000010 10101010
00000001 01010101
00000000 10101010
00000000 01010101
00000000 00101010
00000000 00010101
$

PS: An easier approach would be to match the to_bits() function with a 
to_bytes() function. Then you can implement the shift as a simple string 
manipulation:

def bitshift_right(b, n):
    bits = to_bits(b)
    shifted = ("0" * n + bits)[:len(bits)]
    return to_bytes(shifted)




More information about the Tutor mailing list