我今天在代码库中遇到了|=
运营商并且无法识别它,并且搜索谷歌搜索python "|="
对我没有任何帮助。
测试以下操作的结果会产生以下结果:
>>> from itertools import combinations
>>> def wtf_is_it(left, right):
>>> orig_left = left
>>> left |= right
>>> return '%s |= %s == %s ' % (orig_left, right, left)
>>> results = [wtf_is_it(l, r) for l, r in combinations(xrange(5), 2)]
>>> print '\n'.join(results)
0 |= 1 == 1
0 |= 2 == 2
0 |= 3 == 3
0 |= 4 == 4
1 |= 0 == 1
1 |= 2 == 3
1 |= 3 == 3
1 |= 4 == 5
2 |= 0 == 2
2 |= 1 == 3
2 |= 3 == 3
2 |= 4 == 6
3 |= 0 == 3
3 |= 1 == 3
3 |= 2 == 3
3 |= 4 == 7
4 |= 0 == 4
4 |= 1 == 5
4 |= 2 == 6
4 |= 3 == 7
看起来它是or
,如果右边比左边大,那么它将两者加在一起,否则它会保持原始值?
此运算符的名称是什么,它的值是什么?
答案 0 :(得分:12)
对于整数,它是按位OR复合赋值运算符。与所有复合赋值运算符一样,a |= b
与a = a | b
相同。管道是按位OR的符号。
正如user2357112指出的那样,更丰富的数据类型可以overload this,因为他们认为合适。
假设您有一些想要通过慢速网络传输的二进制值。假设您有6个开关的输出,每个开关的值可以是0或1。
例如,您有一个列表:switches = [0,1,1,0,1,0,0,0]
传输它的天真方式是6个不同的整数值。如果你使用字节来传输值,它总共是6 * 8 = 48位。但是你只能在接收端获得6位信息 - 所以剩下的42位被浪费了。
相反,您可以使用单个字节来存储所有开关的信息。
执行此操作的一种方法是迭代列表,并计算生成的字节。
例如,
val = 0
for i,s in enumerate(switches):
val |= (s << i)
print(val)
此代码段打印22
,如果您要转换为二进制文件,则会看到它是10110或00010110 - 这只是列表的值,向后排序。
(s << i)
生成一个整数,当以二进制表示时,包含单个1和其余0。因此,在循环的每次迭代中,val
变量可能会“累积”另一个位。
我能想到的一个相对简单的现实生活示例是PHP存储它的方式error level constants。
如果查看链接,第一列中的值全部(除最后一个条目外)值为2 ^ n ,n = 0,1,2,3 .. 0.14。
实际上(2 ^ n )对位域和按位运算具有特殊意义。
查看n的前几个值的值:
n | 2^n | 2^n (Binary Representation) ---|-----|---- 0 | 1 | 00001 1 | 2 | 00010 2 | 4 | 00100 3 | 8 | 01000 4 | 16 | 10000
如果在二进制表示中,您从最左边的位置开始向左移动 n 点,您将看到您在单个1的位置结束。这完全是故意的。
回到PHP。让我们说,作为服务器管理员,只对 感兴趣的是各种错误级别的子集。例如,您知道要显示E_ERROR
,E_PARSE
和E_CORE_ERROR
,同时放弃其余内容。
好吧,因为PHP巧妙地为我们刚刚看到的(2 ^ n )值分配了不同的错误级别,我们能够通过单个值表示这些标志的任意组合而不会丢失信息。
我们可以通过采用值的按位OR来计算此组合的值,方法与之前相同。在我们的案例中:
E_ERROR | 1 | 0000 0000 0000 0001 E_PARSE | 4 | 0000 0000 0000 0100 E_CORE_ERROR | 16 | 0000 0000 0001 0000 ---------------------------------------- 21 0000 0000 0001 0101
在python中:
print(1|4|16)
# 21
这种按位OR运算的结果通常称为bitmask。
给定一个位掩码和抛出错误的错误值,您可以快速检查它是否是您感兴趣的东西 - 也就是说,它是E_ERROR
,E_PARSE
类型还是E_CORE_ERROR
- 您可以快速计算位掩码的按位AND和错误值。
此AND运算的结果将为0(在这种情况下,您对错误不感兴趣/它不是您感兴趣的级别之一)或非零(在这种情况下)它是)。验证这个按位AND操作是否按照我的说法进行操作留给你。
最后,您可能已经注意到,只需添加错误值会产生与您从OR-ing获得的值相同的值。在这种情况下,这是真的。那么为什么使用bitwise-OR而不是简单的加法?
答案:因为按位或运算可以多次包含一个值。 这很难解释,所以请考虑最后一个例子:
您希望编写能够确保“监控”给定错误级别的代码。您可以访问将获取和设置位掩码的函数。
使用添加,您可以编写如下内容:
set_mask(get_mask() + E_PARSE)
但如果E_PARSE
的位已经设置,那么实际上取消设置 E_PARSE
,可能更重要的是, >使至少一个附加标志无效 - 可能使位域中的每个标志无效。
显然,这不是你想要的。
相反,如果您使用按位OR运算:
set_mask(get_mask() | E_PARSE)
无论先前是否设置了E_PARSE
,无论您执行此操作多少次,E_PARSE
都会在每次操作后保持设置,并且不会有其他标记无意中受到影响。
(做这一切背后的数学 - 它非常有启发性)
答案 1 :(得分:2)
一个用例是当你需要累积 OR 而不是多个值时,比方说,决定其中一个或多个是 True ,或者如果所有这些都错误。
以下是一些(人为的)例子。
假设您有一份已通过或未通过某个科目的学生名单。如果您需要计算任何学生是否通过了该主题,您可以编写如下内容:
passed = False
for student in students:
passed |= student.passed
if passed:
print("someone passed")
else:
print("no one passed")
同样,如果您在网页上有一个复选框列表,并且您需要拒绝服务(如果选中其中任何一个),您可以编写如下内容:
deny = False
for box in boxes:
deny |= box.checked
答案 2 :(得分:2)
flags()
方法。我使用了类似下面的代码来有条件地构建一个合适的位掩码:
def flags(self, index):
if not index.isValid()
return None
f = QtCore.ItemIsEnabled
if index.column() > some_value:
f |= QtCore.Qt.ItemIsSelectable
if some_other_condition:
f |= QtCore.Qt.ItemIsUserCheckable
return f
答案 3 :(得分:0)
Jedwards已经回答了,但我也会添加一个更通用的答案。
在Python中,如果您看到表单的运算符:
x ¤= y
其中¤
是任何标准二元运算符 - 二元运算符,它需要2个运算符,如+ - * / & |
,它是简写:
x = x ¤ y
因此x |= y
与x = x | y
等效,其中\
是“按位或”运算符,正如x += y
与x = x + y
相同,其中+
是补充。