Python中的左移右移需要需要一些工具:

bin():转换为二进制的函数,比如bin(2)返回值是字符串类型的'0b10'。

二进制在Python中的表达是0b开头的,比如0b10表示的是2的二进制
但是如果使用type(0b10)发现,0b10本身是int类型的。直接使用0b10
程序也会把它直接替换为2.

Python中二进制的负数表示也很简单粗暴,比如-0b10表示的是-2.
由于不采用补码而是直接使用符号位置,所以Python中对负数的左右
移操作将不是简单的补0或者补1.

例子:

bin(-15)       # '-0b1111'
bin(-15>>1)    # '-0b1000',也就是-8

可以看到,因为不是使用补码,所以当-0b1111右移1位的时候,它的数值变成了-0b1000.
这样的情况只发生在最低位是1的情况。事实上,-0b1111>>1的结果刚好是-0b111-1=-0b1000
很有趣,目前没有得出其他结论。这样的厉害之处在于,对负数左移的时候不会出现符号跃迁
的问题,比如-0b101左移一位得到-0b1010,这样使得位移动运算变得安全了起来。

上面的引用部分是早些时候的描述方法,如今看来多有不妥。试图通过-0b1111理解右移无异于试图通过-15理解右移。像理解位移运算,还是要按照计算机底层存储使用的补码的方式来理解。不懂的小伙伴可以大致了解下原码,反码和补码分别对应的格式。Python中的int是动态长度的,理论上可以支持无限大的数字,因而我们也不通过Python来理解位移运算了。看看拓展阅读中的Java里的位移运算会更容易理解。

拓展阅读:

对Java感兴趣的同学可以了解一下什么是Java中的左移,右移,无符号右移。简单来说:

左移就是左边扔掉,右边补0。

下面的两个例子,一个结果是20,一个结果是-1610612736。

10 << 1     // 00000000 00000000 00000000 00001010 -> 00000000 00000000 00000000 00010100
10 << 28    // 00000000 00000000 00000000 00001010 -> 10100000 00000000 00000000 00000000

右移就是左边补充符号位的值,右边扔掉。

10 >> 1 // 答案是5 00000000 00000000 00000000 00000101
-10 >> 1 // 答案是 -5 1111 1111 1111 1111 1111 1111 1111 1011

无符号右移呢,不管你高位是1还是0,无符号右移都补0。

-10 >>> 1 // 答案是2147483643  01111 1111 1111 1111 1111 1111 1111 1011