从位运算看海象运算符

前言

突然发现了Python3.8版本引入的海象运算符,就借着位运算的需求来看看是怎么个用法。

需求

需求是这样的,我有一张表,表中存在很多类东西,每个类都有一个自增编号。为了让自增编号转变为one-hot编码,需要将自增的编号转换为二进制。

当然,确实是可以直接使用Python的二进制转换工具,但那样就完全没意思了不是吗?

先找出需要多少位数

首先,我们需要知道,自增编号的最大值是多少。

既然是表里面存储的,那么这一点就比较好办:

SELECT MAX(id) FROM table_name;

不管你用jdbc也好,ODBC也罢,反正你拿到了这个最大值。于是你开始准备着手计算:

def get_max_length(max_id):
  count = 1
  while max_id := max_id >> 1:
    count += 1
  return count

这就是海象运算符的用法。在判断的时候,先计算海象运算符右侧,然后把结果赋值给左侧,最后判断左值是否满足条件。

使用限制

当然,这并不是Go语言,所以海象运算符并不是哪里都能用。

赋值场景

在赋值过程中,如果搭配括号,那么海象运算符与赋值符号是完全一致的。

a = (a - 30) / 2

这个看着相当简单。而如果我说可以用海象运算符装个莫名其妙的逼呢?

a = (a := (a := a - 30) / 2)

看起来很诡异,但是原理上与传统的赋值符号用法完全一致。毕竟二者都是一个顺序:

先计算右值、再赋给左值。

当然,二者也不是完全不同。海象运算符不可以直接赋值

传统赋值过程中,如果我们是可以直接指定的:

a = 30

海象运算符不一样,会报错:

a := 30
~~^^~~~

这就是为什么,我们在装逼的时候,最左边的赋值还只能是=符号。

判断场景

海象运算符最大的特点就是,本身返回的是值,所以判断场景才是海象运算符最常用的场景。就比如说,我需要移位,传统过程只能这么做:

a = a >> 1
if a > 0:
  print(a)

因为=没有返回值,只能将右值给到左值。

海象运算符不一样,在将右值给到左值的基础上,还能够把左值返回出去:

if a := a >> 1:
  print(a)

不过需要注意的是,海象运算符的优先级比较低,在真实场景使用的时候需要带上括号:

if a := 30 > 40:
  print(a) # 不输出
print(a)   # 输出False,因为优先级算了30 > 40

转为one-hot编码

当然,由于是one-hot编码,我们并不能直接使用二进制数值,因为这样做无法转为矩阵。

不过好在,我们还有海象运算符,我们可以这么做:

def transfer2b(num):
  # 先把最初的一位数加进去
  onehot = [num & 1]
  # 海象运算符循环处理
  while num := num >> 1:
    # 使用切片的方式增加数据
    onehot[:0] = [num & 1]
    # 由于并非极端场景,所以与`insert`差距不大
    # 下面是`insert`写法:
    # onehot.insert(0, num & 1)
  return onehot

那么我们在使用的时候就会很方便:

print(transfer2b(64)) # 输出:[1, 0, 0, 0, 0, 0, 0]

一件小事情

最开始的时候,我始终认为 64 64 64是只需要 6 6 6位二进制,后来才想起来,用二进制表示的时候还有一个 0 0 0需要表示。

所以,如果是 64 64 64,其实需要 7 7 7位,因为 6 6 6位只能够表示 0 ∼ 2 6 − 1 0\sim2^6-1 0261。数字虽然确实是有 64 64 64个,但由于从 0 0 0开始,所以实际最大也就少了一个。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ordinary_brony

代码滞销,救救码农

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值