关于python:布尔运算符与按位运算符

Boolean operators vs Bitwise operators

我对什么时候应该使用Boolean和Bitwise运算符感到困惑

1
and vs &, or vs |

有人能告诉我什么时候使用每一个,什么时候使用一个对另一个会影响我的结果吗?


以下是一些指导原则:

  • 布尔运算符通常用于布尔值,但位运算符通常用于整数值。
  • 布尔运算符短路,但位运算符不短路。

短路行为在以下表达式中很有用:

1
2
if x is not None and x.foo == 42:
    # ...

这对于按位的&运算符不能正确工作,因为总是对两边进行评估,从而给出AttributeError: 'NoneType' object has no attribute 'foo'。当使用Boolean and运算符时,当第一个表达式为false时,不会计算第二个表达式。同样地,如果第一个论点是真的,那么or也不评价第二个论点。


理论上,andor直接来自布尔逻辑(因此操作两个布尔值以产生布尔值),而&|将布尔值和/或应用于整数的单个位。关于后者是如何工作的,这里有很多问题。

以下是可能影响结果的实际差异:

  • andor短路,即True or sys.exit(1)不会退出,因为对于第一个操作数的某个值(True or ...False and ...,第二个操作数不会改变结果=不需要评估。但是|&不短路——True | sys.exit(1)把你从回复中赶了出来。
  • (仅适用于某些?带有运算符重载的语言,包括python:)&|是常规运算符,可以重载—andor被转换为语言(尽管至少在python中,强制布尔值的特殊方法可能有副作用)。
  • (仅适用于少数语言[参见KennyTM的评论]:andor返回(总是?从来没有真正理解过这个,我也不需要它)操作数的值,而不是TrueFalse。这并没有改变条件中布尔表达式的含义——1 or True1,但1也是正确的。但它曾经被用来模拟条件运算符(C语法中的cond ? true_val : false_val,python中的true_val if cond else false_val,几年来一直使用)。对于&|,结果类型取决于操作数如何重载各自的特殊方法(True & FalseFalse99 & 73,对于集合,它是联合/交集…)。
  • 但是,即使在a_boolean & another_boolean的工作方式相同的情况下,正确的解决方案还是使用and,这仅仅是因为andor与布尔表达式和条件有关,而&|则代表位旋转。


    还有一个更大的区别,这让我困惑了一段时间:由于&和其他位运算符的优先级高于and和其他布尔运算符,以下表达式对不同的值进行了计算:

    1
    0 < 1 & 0 < 2

    对战

    1
    0 < 1 and 0 < 2

    也就是说,第一个生成的False,因为它相当于0 < (1 & 0) < 2,因此0 < 0 < 2,因此0 < 0 and 0 < 2


    如果您试图在numpy中执行元素相关的布尔运算,那么答案会有所不同。可以使用&|进行元素级布尔运算,但andor会返回值错误。

    为了安全起见,您可以使用numpy逻辑函数。

    1
    2
    3
    4
    5
    6
    7
    8
    np.array([True, False, True]) | np.array([True, False, False])
    # array([ True, False,  True], dtype=bool)

    np.array([True, False, True]) or np.array([True, False, False])
    # ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

    np.logical_or(np.array([True, False, True]), np.array([True, False, False]))
    # array([ True, False,  True], dtype=bool)

    提示的名称为:

    • 布尔运算符用于执行逻辑操作(编程和形式逻辑中常见的真值测试)
    • 位运算符用于"位旋转"(字节和数字数据类型中位的低级操作)

    虽然使用位运算符执行逻辑操作是可能的,而且有时确实是可取的(通常是出于效率原因),但为了防止细微的错误和不必要的副作用,通常应避免使用位运算符。

    如果需要操作位,则位运算符是专门构建的。这本有趣的书:黑客之乐包含了一些很酷和真正有用的例子,这些例子说明了通过小旋转可以实现什么。


    布尔运算是逻辑运算。

    位操作是对二进制位的操作。

    按位运算:

    1
    2
    3
    4
    5
    6
    >>> k = 1
    >>> z = 3
    >>> k & z  
    1
    >>> k | z  
    3

    操作:

    1
    2
    3
    4
    And & 1 if both bits are 1, 0 otherwise
    Or  | 1 if either bit is 1
    Xor ^ 1 if the bits are different, 0 if they're the same
    Not ~ Flip each bit

    位运算的一些用法:

    1)设置和清除位

    布尔运算:

    1
    2
    3
    4
    5
    6
    7
    >>> k = True
    >>> z = False
    >>> k & z  # and
    False
    >>> k | z  # or
    True
    >>>


    一般规则是对现有操作数使用适当的运算符。对布尔操作数使用布尔(逻辑)运算符,对(更宽)整数操作数使用位运算符(注意:false等于0,true等于1)。唯一"棘手"的情况是将布尔运算符应用于非布尔操作数。让我们举一个简单的例子,如[so]:python-"and"和"and"[duplicate]:5 & 75 and 7之间的差异。

    对于按位和(&;),事情非常简单:

    1
    2
    3
    4
    5     = 0b101
    7     = 0b111
    -----------------
    5 &amp; 7 = 0b101 = 5

    对于逻辑与,这里是的内容:布尔操作状态(重点是我的):

    (Note that neither and nor or restrict the value and type they return to False and True, but rather return the last evaluated argument.

    例子:

    1
    2
    3
    4
    >>> 5 and 7
    7
    >>> 7 and 5
    5

    当然,这同样适用于与或。


    布尔值'和'对位'&;':

    伪代码/python帮助我理解了这两者之间的区别:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    def boolAnd(A, B):
        # boolean 'and' returns either A or B
        if A == False:
            return A
        else:
            return B

    def bitwiseAnd(A , B):
        # binary representation (e.g. 9 is '1001', 1 is '0001', etc.)

        binA = binary(A)
        binB = binary(B)



        # perform boolean 'and' on each pair of binaries in (A, B)
        # then return the result:
        # equivalent to: return ''.join([x*y for (x,y) in zip(binA, binB)])

        # assuming binA and binB are the same length
        result = []
        for i in range(len(binA)):
          compar = boolAnd(binA[i], binB[i])
          result.append(compar)

        # we want to return a string of 1s and 0s, not a list

        return ''.join(result)