Python 'and' (boolean) vs '&' (bitwise) - 为什么列表与 numpy 数组的行为不同?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22646463/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 01:21:17  来源:igfitidea点击:

'and' (boolean) vs '&' (bitwise) - Why difference in behavior with lists vs numpy arrays?

pythonnumpybit-manipulationboolean-expressionampersand

提问by rysqui

What explains the difference in behavior of boolean and bitwise operations on lists vs NumPy arrays?

什么解释了列表与 NumPy 数组上布尔运算和按位运算的行为差异?

I'm confused about the appropriate use of &vs andin Python, illustrated in the following examples.

&and在 Python 中正确使用vs感到困惑,如下例所示。

mylist1 = [True,  True,  True, False,  True]
mylist2 = [False, True, False,  True, False]

>>> len(mylist1) == len(mylist2)
True

# ---- Example 1 ----
>>> mylist1 and mylist2
[False, True, False, True, False]
# I would have expected [False, True, False, False, False]

# ---- Example 2 ----
>>> mylist1 & mylist2
TypeError: unsupported operand type(s) for &: 'list' and 'list'
# Why not just like example 1?

>>> import numpy as np

# ---- Example 3 ----
>>> np.array(mylist1) and np.array(mylist2)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
# Why not just like Example 4?

# ---- Example 4 ----
>>> np.array(mylist1) & np.array(mylist2)
array([False,  True, False, False, False], dtype=bool)
# This is the output I was expecting!

This answerand this answerhelped me understand that andis a boolean operation but &is a bitwise operation.

这个答案这个答案帮助我理解这and是一个布尔运算,但它&是一个按位运算。

I read about bitwise operationsto better understand the concept, but I am struggling to use that information to make sense of my above 4 examples.

我阅读了按位运算以更好地理解这个概念,但我正在努力使用这些信息来理解我上面的 4 个例子。

Example 4 led me to my desired output, so that is fine, but I am still confused about when/how/why I should use andvs &. Why do lists and NumPy arrays behave differently with these operators?

示例 4 使我获得了所需的输出,所以很好,但我仍然对何时/如何/为什么应该使用andvs感到困惑&。为什么列表和 NumPy 数组在使用这些运算符时表现不同?

Can anyone help me understand the difference between boolean and bitwise operations to explain why they handle lists and NumPy arrays differently?

谁能帮助我理解布尔运算和按位运算之间的区别,以解释为什么它们以不同的方式处理列表和 NumPy 数组?

采纳答案by ramcdougal

andtests whether both expressions are logically Truewhile &(when used with True/Falsevalues) tests if both are True.

and测试两个表达式是否符合逻辑Truewhile &(与True/False值一起使用时)测试两个表达式是否都是True.

In Python, empty built-in objects are typically treated as logically Falsewhile non-empty built-ins are logically True. This facilitates the common use case where you want to do something if a list is empty and something else if the list is not. Note that this means that the list [False] is logically True:

在 Python 中,空内置对象通常在逻辑上被视为False,而非空内置对象在逻辑上被视为True. 这有助于常见用例,如果列表为空,您想要做某事,如果列表不是,则做其他事情。请注意,这意味着列表 [False] 在逻辑上是True

>>> if [False]:
...    print 'True'
...
True

So in Example 1, the first list is non-empty and therefore logically True, so the truth value of the andis the same as that of the second list. (In our case, the second list is non-empty and therefore logically True, but identifying that would require an unnecessary step of calculation.)

因此在示例 1 中,第一个列表是非空的,因此在逻辑上True,因此 的真值and与第二个列表的真值相同。(在我们的例子中,第二个列表是非空的,因此在逻辑上是True,但识别它需要一个不必要的计算步骤。)

For example 2, lists cannot meaningfully be combined in a bitwise fashion because they can contain arbitrary unlike elements. Things that can be combined bitwise include: Trues and Falses, integers.

例如 2,列表不能以按位方式进行有意义的组合,因为它们可以包含任意不同的元素。可以按位组合的事物包括:Trues 和 Falses、整数。

NumPy objects, by contrast, support vectorized calculations. That is, they let you perform the same operations on multiple pieces of data.

相比之下,NumPy 对象支持矢量化计算。也就是说,它们允许您对多条数据执行相同的操作。

Example 3 fails because NumPy arrays (of length > 1) have no truth value as this prevents vector-based logic confusion.

示例 3 失败,因为 NumPy 数组(长度 > 1)没有真值,因为这可以防止基于向量的逻辑混淆。

Example 4 is simply a vectorized bit andoperation.

示例 4 只是一个矢量化位and操作。

Bottom Line

底线

  • If you are not dealing with arrays and are not performing math manipulations of integers, you probably want and.

  • If you have vectors of truth values that you wish to combine, use numpywith &.

  • 如果您不处理数组并且不执行整数的数学运算,您可能需要and.

  • 如果您有想要组合的真值向量,请使用numpywith &

回答by Zaur Nasibov

  1. In Python an expression of X and Yreturns Y, given that bool(X) == Trueor any of Xor Yevaluate to False, e.g.:

    True and 20 
    >>> 20
    
    False and 20
    >>> False
    
    20 and []
    >>> []
    
  2. Bitwise operator is simply not defined for lists. But it is defined for integers - operating over the binary representation of the numbers. Consider 16 (01000) and 31 (11111):

    16 & 31
    >>> 16
    
  3. NumPy is not a psychic, it does not know, whether you mean that e.g. [False, False]should be equal to Truein a logical expression. In this it overrides a standard Python behaviour, which is: "Any empty collection with len(collection) == 0is False".

  4. Probably an expected behaviour of NumPy's arrays's & operator.

  1. 在 Python 中,X and Y返回的表达式Y,给定bool(X) == True或任何XY评估为 False,例如:

    True and 20 
    >>> 20
    
    False and 20
    >>> False
    
    20 and []
    >>> []
    
  2. 按位运算符根本没有为列表定义。但它是为整数定义的——对数字的二进制表示进行操作。考虑 16 (01000) 和 31 (11111):

    16 & 31
    >>> 16
    
  3. NumPy 不是通灵者,它不知道您的意思是否是逻辑表达式中的 eg[False, False]应该等于True。在这方面,它覆盖了标准的 Python 行为,即:“任何带有len(collection) == 0is 的空集合False”。

  4. 可能是 NumPy 数组的 & 运算符的预期行为。

回答by ramcdougal

The short-circuiting boolean operators (and, or) can't be overriden because there is no satisfying way to do this without introducing new language features or sacrificing short circuiting. As you may or may not know, they evaluate the first operand for its truth value, and depending on that value, either evaluate and return the second argument, or don't evaluate the second argument and return the first:

短路布尔运算符 ( and, or) 不能被覆盖,因为在不引入新的语言功能或牺牲短路的情况下,没有令人满意的方法来做到这一点。您可能知道也可能不知道,它们评估第一个操作数的真值,并根据该值,评估并返回第二个参数,或者不评估第二个参数并返回第一个:

something_true and x -> x
something_false and x -> something_false
something_true or x -> something_true
something_false or x -> x

Note that the (result of evaluating the) actual operand is returned, not truth value thereof.

请注意,返回的是(评估结果)实际操作数,而不是其真值。

The only way to customize their behavior is to override __nonzero__(renamed to __bool__in Python 3), so you can affect which operand gets returned, but not return something different. Lists (and other collections) are defined to be "truthy" when they contain anything at all, and "falsey" when they are empty.

自定义其行为的唯一方法是覆盖__nonzero____bool__在 Python 3 中重命名为),因此您可以影响返回的操作数,但不会返回不同的内容。列表(和其他集合)在包含任何内容时被定义为“真实”,当它们为空时被定义为“虚假”。

NumPy arrays reject that notion: For the use cases they aim at, two different notions of truth are common: (1) Whether any element is true, and (2) whether all elements are true. Since these two are completely (and silently) incompatible, and neither is clearly more correct or more common, NumPy refuses to guess and requires you to explicitly use .any()or .all().

NumPy 数组拒绝这个概念:对于它们所针对的用例,两种不同的真值概念是常见的:(1) 是否有任何元素为真,以及 (2) 是否所有元素都为真。由于这两者完全(并且默默地)不兼容,并且显然都不是更正确或更常见,因此 NumPy 拒绝猜测并要求您明确使用.any().all()

&and |(and not, by the way) canbe fully overriden, as they don't short circuit. They can return anything at all when overriden, and NumPy makes good use of that to do element-wise operations, as they do with practically any other scalar operation. Lists, on the other hand, don't broadcast operations across their elements. Just as mylist1 - mylist2doesn't mean anything and mylist1 + mylist2means something completely different, there is no &operator for lists.

&and |(和not,顺便说一下)可以完全覆盖,因为它们不会短路。它们在被覆盖时可以返回任何内容,而 NumPy 很好地利用了这一点来进行元素操作,就像它们实际上处理任何其他标量操作一样。另一方面,列表不会在其元素之间广播操作。就像mylist1 - mylist2没有任何意义并且mylist1 + mylist2意味着完全不同的东西一样,&列表没有运算符。

回答by knbk

Operations with a Python list operate on the list. list1 and list2will check if list1is empty, and return list1if it is, and list2if it isn't. list1 + list2will append list2to list1, so you get a new list with len(list1) + len(list2)elements.

用Python列表操作上操作列表list1 and list2将检查是否list1为空,如果是则返回,list1如果不是则返回list2list1 + list2将附加list2list1,因此您将获得一个包含len(list1) + len(list2)元素的新列表。

Operators that only make sense when applied element-wise, such as &, raise a TypeError, as element-wise operations aren't supported without looping through the elements.

仅在按元素应用时才有意义的运算符,例如&, raise a TypeError,因为不循环遍历元素时不支持按元素操作。

Numpy arrays support element-wiseoperations. array1 & array2will calculate the bitwise or for each corresponding element in array1and array2. array1 + array2will calculate the sum for each corresponding element in array1and array2.

Numpy 数组支持逐元素操作。array1 & array2将计算的按位或用于在每个相应元件array1array2array1 + array2将计算在每个相应元素的总和array1array2

This does not work for andand or.

这不适用于andor

array1 and array2is essentially a short-hand for the following code:

array1 and array2本质上是以下代码的简写:

if bool(array1):
    return array2
else:
    return array1

For this you need a good definition of bool(array1). For global operations like used on Python lists, the definition is that bool(list) == Trueif listis not empty, and Falseif it is empty. For numpy's element-wise operations, there is some disambiguity whether to check if any element evaluates to True, or all elements evaluate to True. Because both are arguably correct, numpy doesn't guess and raises a ValueErrorwhen bool()is (indirectly) called on an array.

为此,您需要对bool(array1). 对于像在 Python 列表上使用的全局操作,定义是bool(list) == Trueiflist不为空,False如果为空。对于 numpy 的逐元素操作,是否检查是否有任何元素计算为True,或所有元素计算为,存在一定的歧义True。因为两者都可以说是正确的,所以 numpy 不会猜测并引发一个ValueErrorwhen bool()(间接)在数组上调用。

回答by Seth

Example 1:

示例 1:

This is how the andoperator works.

这就是and运算符的工作方式。

xand y=> if xis false, then x, else y

xy=> 如果x为假,则为x,否则为y

So in other words, since mylist1is not False, the result of the expression is mylist2. (Only empty listsevaluate to False.)

所以换句话说,由于mylist1不是False,表达式的结果是mylist2。(只有空列表评估为False。)

Example 2:

示例 2:

The &operator is for a bitwise and, as you mention. Bitwise operations only work on numbers. The result of a& bis a number composed of 1s in bits that are 1 in both aand b. For example:

&操作是按位,正如你提到。按位运算仅适用于数字。a& b的结果是一个由 1 组成的数字,在ab中都为 1 。例如:

>>> 3 & 1
1

It's easier to see what's happening using a binary literal(same numbers as above):

使用二进制文字(与上面相同的数字)更容易看到发生了什么:

>>> 0b0011 & 0b0001
0b0001

Bitwise operations are similar in concept to boolean (truth) operations, but they work only on bits.

按位运算在概念上类似于布尔(真值)运算,但它们仅适用于位。

So, given a couple statements about my car

所以,给出一些关于我的车的陈述

  1. My car is red
  2. My car has wheels
  1. 我的车是红色的
  2. 我的车有轮子

The logical "and" of these two statements is:

这两个语句的逻辑“与”是:

(is my car red?) and (does car have wheels?) => logical true of false value

(我的车是红色的吗?)和(车有轮子吗?)=> 假值的逻辑真

Both of which are true, for my car at least. So the value of the statement as a whole is logicallytrue.

这两个都是真的,至少对我的车来说是这样。所以整个语句的价值在逻辑上是正确的。

The bitwise "and" of these two statements is a little more nebulous:

这两个语句的按位“和”有点模糊:

(the numeric value of the statement 'my car is red') & (the numeric value of the statement 'my car has wheels') => number

('my car is red'语句的数值)&('my car has wheel'语句的数值)=> number

If python knows how to convert the statements to numeric values, then it will do so and compute the bitwise-and of the two values. This may lead you to believe that &is interchangeable with and, but as with the above example they are different things. Also, for the objects that can't be converted, you'll just get a TypeError.

如果 python 知道如何将语句转换为数值,那么它会这样做并计算两个值的按位与。这可能会让您相信&可以与 互换and,但与上面的示例一样,它们是不同的东西。此外,对于无法转换的对象,您只会得到一个TypeError.

Example 3 and 4:

示例 3 和 4:

Numpy implements arithmetic operationsfor arrays:

Numpy为数组实现算术运算

Arithmetic and comparison operations on ndarrays are defined as element-wise operations, and generally yield ndarray objects as results.

ndarray 上的算术和比较操作被定义为逐元素操作,并且通常产生 ndarray 对象作为结果。

But does not implement logical operations for arrays, because you can't overload logical operators in python. That's why example three doesn't work, but example four does.

但是不为数组实现逻辑操作,因为你不能在 python 中重载逻辑运算符。这就是示例三不起作用而示例四起作用的原因。

So to answer your andvs &question: Use and.

所以要回答你的andvs&问题:使用and.

The bitwise operations are used for examining the structure of a number (which bits are set, which bits aren't set). This kind of information is mostly used in low-level operating system interfaces (unix permission bits, for example). Most python programs won't need to know that.

按位运算用于检查数字的结构(设置哪些位,未设置哪些位)。此类信息主要用于低级操作系统接口(例如unix 权限位)。大多数python程序不需要知道这一点。

The logical operations (and, or, not), however, are used all the time.

然而,逻辑运算 ( and, or, not) 一直在使用。

回答by MoiTux

For the first example and base on the django's doc
It will always return the second list, indeed a non empty list is see as a True value for Python thus python return the 'last' True value so the second list

对于第一个示例并基于django 的文档
,它将始终返回第二个列表,实际上,将非空列表视为 Python 的 True 值,因此 python 返回“最后一个”True 值,因此第二个列表

In [74]: mylist1 = [False]
In [75]: mylist2 = [False, True, False,  True, False]
In [76]: mylist1 and mylist2
Out[76]: [False, True, False, True, False]
In [77]: mylist2 and mylist1
Out[77]: [False]

回答by Veky

About list

关于 list

First a very important point, from which everything will follow (I hope).

首先是非常重要的一点,一切都会随之而来(我希望)。

In ordinary Python, listis not special in any way (except having cute syntax for constructing, which is mostly a historical accident). Once a list [3,2,6]is made, it is for all intents and purposes just an ordinary Python object, like a number 3, set {3,7}, or a function lambda x: x+5.

在普通的 Python 中,list没有任何特别之处(除了有可爱的构造语法,这主要是历史意外)。一旦创建了列表[3,2,6],就所有意图和目的而言,它都只是一个普通的 Python 对象,例如 number 3、 set{3,7}或 function lambda x: x+5

(Yes, it supports changing its elements, and it supports iteration, and many other things, but that's just what a type is: it supports some operations, while not supporting some others. int supports raising to a power, but that doesn't make it very special - it's just what an int is. lambda supports calling, but that doesn't make it very special - that's what lambda is for, after all:).

(是的,它支持改变它的元素,它支持迭代,以及许多其他的东西,但这就是类型:它支持一些操作,而不支持一些其他操作。int 支持提升到一个幂,但这不是让它变得非常特别 - 这就是 int 的含义。lambda 支持调用,但这并不使它非常特别 - 毕竟这就是 lambda 的用途:)。

About and

关于 and

andis not an operator (you can call it "operator", but you can call "for" an operator too:). Operators in Python are (implemented through) methods called on objects of some type, usually written as part of that type. There is no way for a method to hold an evaluation of some of its operands, but andcan (and must) do that.

and不是运算符(您可以称其为“运算符”,但您也可以将其称为“for”运算符:)。Python 中的运算符是(通过)在某种类型的对象上调用的方法,通常作为该类型的一部分编写。一种方法无法对其某些操作数进行评估,但and可以(并且必须)这样做。

The consequence of that is that andcannot be overloaded, just like forcannot be overloaded. It is completely general, and communicates through a specified protocol. What you cando is customize your part of the protocol, but that doesn't mean you can alter the behavior of andcompletely. The protocol is:

这样做的结果是and不能重载,就像for不能重载一样。它是完全通用的,并通过指定的协议进行通信。您可以做的是自定义您的协议部分,但这并不意味着您可以and完全改变其行为。协议是:

Imagine Python interpreting "a and b" (this doesn't happen literally this way, but it helps understanding). When it comes to "and", it looks at the object it has just evaluated (a), and asks it: are you true? (NOT: are you True?) If you are an author of a's class, you can customize this answer. If aanswers "no", and(skips b completely, it is not evaluated at all, and) says: ais my result (NOT: False is my result).

想象一下 Python 解释“a 和 b”(这不会按字面意思发生,但有助于理解)。当谈到“and”时,它会查看它刚刚评估的对象(a),并问它:你是真的吗?(不是:你是True吗?)如果你是 a 类的作者,你可以自定义这个答案。如果a回答“否”,and(完全跳过 b,它根本不被评估,并且)说:a是我的结果(不是:假是我的结果)。

If adoesn't answer, andasks it: what is your length? (Again, you can customize this as an author of a's class). If aanswers 0, anddoes the same as above - considers it false (NOTFalse), skips b, and gives aas result.

如果a没有回答,and问它:你的长度是多少?(同样,您可以将其自定义为a's 类的作者)。如果a回答 0,and则与上述相同 - 将其视为错误(错误),跳过 b,并给出a结果。

If aanswers something other than 0 to the second question ("what is your length"), or it doesn't answer at all, or it answers "yes" to the first one ("are you true"), andevaluates b, and says: bis my result. Note that it does NOTask bany questions.

如果a对第二个问题(“你的长度是多少”)的回答不是 0,或者它根本不回答,或者它对第一个问题回答“是”(“你是真的吗”),则and计算 b,并且说:b是我的结果。请注意,它b任何问题。

The other way to say all of this is that a and bis almost the same as b if a else a, except a is evaluated only once.

换句话说,这与a and b几乎相同b if a else a,只是 a 只计算一次。

Now sit for a few minutes with a pen and paper, and convince yourself that when {a,b} is a subset of {True,False}, it works exactly as you would expect of Boolean operators. But I hope I have convinced you it is much more general, and as you'll see, much more useful this way.

现在用笔和纸坐几分钟,让自己相信当 {a,b} 是 {True,False} 的子集时,它的工作方式与您对布尔运算符的期望完全相同。但我希望我已经让你相信它更通用,而且你会看到,这种方式更有用。

Putting those two together

把这两个放在一起

Now I hope you understand your example 1. anddoesn't care if mylist1 is a number, list, lambda or an object of a class Argmhbl. It just cares about mylist1's answer to the questions of the protocol. And of course, mylist1 answers 5 to the question about length, so and returns mylist2. And that's it. It has nothing to do with elements of mylist1 and mylist2 - they don't enter the picture anywhere.

现在我希望你理解你的例子 1.and不关心 mylist1 是数字、列表、lambda 还是类 Argmhbl 的对象。它只关心 mylist1 对协议问题的回答。当然,mylist1 对有关长度的问题回答了 5,因此返回 mylist2。就是这样。它与 mylist1 和 mylist2 的元素无关——它们不会在任何地方输入图片。

Second example: &on list

第二个例子:&list

On the other hand, &is an operator like any other, like +for example. It can be defined for a type by defining a special method on that class. intdefines it as bitwise "and", and bool defines it as logical "and", but that's just one option: for example, sets and some other objects like dict keys views define it as a set intersection. listjust doesn't define it, probably because Guido didn't think of any obvious way of defining it.

另一方面,&是一个像任何其他人一样的运营商,+例如。可以通过在该类上定义特殊方法来为该类型定义它。int将其定义为按位“与”,而 bool 将其定义为逻辑“与”,但这只是一种选择:例如,集合和其他一些对象(如 dict 键视图)将其定义为集合交集。list只是没有定义它,可能是因为 Guido 没有想到任何明显的定义方法。

numpy

麻木的

On the other leg:-D, numpy arrays arespecial, or at least they are trying to be. Of course, numpy.array is just a class, it cannot override andin any way, so it does the next best thing: when asked "are you true", numpy.array raises a ValueError, effectively saying "please rephrase the question, my view of truth doesn't fit into your model". (Note that the ValueError message doesn't speak about and- because numpy.array doesn't know whois asking it the question; it just speaks about truth.)

另一方面:-D,numpy 数组特殊的,或者至少它们正试图成为。当然, numpy.array 只是一个类,它不能and以任何方式覆盖,所以它做了下一件最好的事情:当被问到“你是真的吗”时,numpy.array 引发了一个 ValueError,实际上是说“请重新表述这个问题,我的真理观不适合你的模型”。(请注意, ValueError 消息并没有谈论and- 因为 numpy.array 不知道是在问这个问题;它只是谈论真相。)

For &, it's completely different story. numpy.array can define it as it wishes, and it defines &consistently with other operators: pointwise. So you finally get what you want.

对于&,这是完全不同的故事。numpy.array 可以按照自己的意愿定义它,并且它定义&与其他运算符一致:逐点。所以你终于得到了你想要的。

HTH,

哈,

回答by S.S.Prabhu

Good question. Similar to the observation you have about examples 1 and 4 (or should I say 1 & 4 :) ) over logical andbitwise &operators, I experienced on sumoperator. The numpy sumand py sumbehave differently as well. For example:

好问题。类似于您对逻辑and按位运算&符的示例 1 和 4(或者我应该说 1 和 4 :))的观察,我在sum运算符上有经验。numpysum和 py 的sum行为也不同。例如:

Suppose "mat" is a numpy 5x5 2d array such as:

假设“mat”是一个 numpy 5x5 二维数组,例如:

array([[ 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]])

Then numpy.sum(mat) gives total sum of the entire matrix. Whereas the built-in sum from Python such as sum(mat) totals along the axis only. See below:

然后 numpy.sum(mat) 给出整个矩阵的总和。而来自 Python 的内置总和,例如 sum(mat) 仅沿轴总计。见下文:

np.sum(mat)  ## --> gives 325
sum(mat)     ## --> gives array([55, 60, 65, 70, 75])