python中'和'(布尔)与'&'(按位)之间的区别。 为什么在列表与numpy数组的行为差异?

什么解释列表与布尔运算和按位运算的差异numpy.arrays?

我对Python中' & 'vs' and '的适当使用感到困惑,在下面的简单例子中进行了说明。

  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 am confused: I would have expected [False, True, False, False, False] # ---- Example 2 ---- >>>mylist1 & mylist2 *** TypeError: unsupported operand type(s) for &: 'list' and 'list' #I am confused: Why not just like example 1? # ---- Example 3 ---- >>>import numpy as np >>> 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() #I am confused: 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! 

这个答案和这个答案都帮助我理解'和'是一个布尔操作,但'&'是一个按位操作。

我正在阅读一些信息,以便更好地理解按位操作的概念,但我正在努力使用这些信息来理解我的上述4个示例。

请注意,在我的特定情况下,我的期望输出是一个新的列表,其中:

  len(newlist) == len(mylist1) newlist[i] == (mylist1[i] and mylist2[i]) #for every element of newlist 

上面的例子4使我得到了我想要的输出,所以这很好。

但是我对于何时/如何/为什么要使用'and'vs'&'感到困惑。 为什么列表和numpy数组的行为与这些运算符有所不同?

任何人都可以帮助我理解布尔操作和按位操作之间的区别,以解释为什么它们以不同的方式处理列表和numpy.arrays?

我只是想确保我继续正确地继续使用这些操作。 非常感谢您的帮助!

 Numpy version 1.7.1 python 2.7 References all inline with text. 

EDITS

1)感谢@delnan指出,在我最初的例子中,我含糊不清,掩盖了我更深的困惑。 我已经更新了我的例子来澄清我的问题。

andtesting两个expression式是否为逻辑True& (与True / False值一起使用时)是否都为True

在Python中,空内置对象通常被视为逻辑False ,而非空内置对象逻辑True 。 这有利于常用的情况下,如果列表是空的,而列表不是, 请注意,这意味着列表[False]在逻辑上为True

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

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

例如2,列表不能有意义的按位组合,因为它们可以包含任意不同的元素。 可以合并的东西包括:Trues和Falses,整数。

NumPy对象支持向量化计算。 也就是说,他们让你对多个数据执行相同的操作。

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

例4只是一个vector化位and操作。

底线

  • 如果你不处理数组,并且不执行整数的math操作,那么你可能需要and

  • 如果你有想要结合的真值的向量,使用numpy&

短路布尔运算符( andor )不能被覆盖,因为没有引入新的语言特性或牺牲短路,没有令人满意的方式来做到这一点。 你可能会也可能不知道,他们评估其真值的第一个操作数,并根据该值,计算并返回第二个参数,或者不评估第二个参数并返回第一个:

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

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

自定义行为的唯一方法是重写__nonzero__ (在Python 3中重命名为__bool__ ),这样可以影响返回的操作数,但不会返回不同的结果。 当它们包含任何东西时,列表(和其他集合)被定义为“真实的”,当它们是空的时候是“假的”。

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

&| (而not ,顺便说一下) 可以完全重写,因为它们不会短路。 当被覆盖时,它们可以返回任何东西,而NumPy则可以很好地利用它来执行元素操作,就像实际上任何其他标量操作一样。 另一方面,列表不会在其元素上广播操作。 就像mylist1 - mylist2并不意味着什么, mylist1 + mylist2意味着完全不同的东西,没有列表的&运算符。

关于list

首先是非常重要的一点,一切都将遵循(我希望)。

在普通的Python中, list并不是什么特别之处(除了构造可爱的语法,这大部分是历史事件)。 一旦列表[3,2,6]被创build,那么所有的意图和目的都只是一个普通的Python对象,如数字3 ,集合{3,7}或函数lambda x: x+5

(是的,它支持改变它的元素,支持迭代等等,但是这只是一个types:它支持一些操作,而不支持其他一些操作。int支持提升权力,但是不支持使它非常特殊 – 它只是一个int,lambda支持调用,但这并没有使它变得非常特别 – 这就是lambda所要求的,毕竟:)。

关于and

并不是运营商(你可以称之为“运营商”,但你也可以给“运营商”打电话:)。 Python中的操作符是通过调用某种types的对象的方法实现的,通常被写为该types的一部分。 一个方法没有办法对一些操作数进行评估,但是可以(而且必须)这样做。

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

想象一下Python解释“a和b”(这种方式不是这样发生的,但它有助于理解)。 当涉及到“和”时,它看着它刚刚评估过的对象(a),并问:你是真的吗? ( 不是 :你是True ?)如果你是一个类的作者,你可以自定义这个答案。 如果答案是“否”, and (完全跳过b,则根本不评估),并且说: a是我的结果( 不是 :False是我的结果)。

如果a人不回答, and问:你的长度是多less? (再次,您可以将其定制为类的作者)。 如果答案为0, and与上面相同 – 认为它是假的( False),则跳过b,并给出结果。

如果对第二个问题(“你的长度”是0)以外a答案进行回答,或者根本不回答,或者对第一个回答“是”(“你是真实的”),则评估b ,并说: b是我的结果。 请注意,它不询问任何问题。

另一种说法是, a and b几乎a and b相同, b if a else a ,除了a只被评估一次。

现在坐上几分钟的笔和纸,说服自己,当{a,b}是{True,False}的一个子集时,它和你所期望的布尔运算符完全一样。 但是我希望我已经说服了你,这是更普遍的,正如你所看到的,这种方式更有用。

把这两个放在一起

现在我希望你能理解你的例子1 and不关心mylist1是一个数字,列表,lambda还是一个类Argmhbl的对象。 它只关心mylist1对协议问题的回答。 当然,mylist1回答5的长度问题,所以返回mylist2。 就是这样。 它与mylist1和mylist2的元素无关 – 它们不会在任何地方input图片。

第二个例子: & on list

另一方面, &就像任何其他的操作符一样,例如+ 。 它可以通过在该类上定义一个特殊的方法来为一个types定义。 int将其定义为按位“和”,而bool将其定义为逻辑“和”,但这只是一个select:例如,集合和其他一些对象,如dict键视图将其定义为集合交集。 list只是没有定义它,可能是因为Guido没有想到明确的方式来定义它。

numpy的

另一方面:-D,numpy数组特殊的,或者至less他们试图成为。 当然,numpy.array只是一个类,它不能以任何方式覆盖,所以它会做下一个最好的事情:当被问及“你是真的”时,numpy.array引发了一个ValueError,有效地说“请重新提出这个问题,我对事实的看法不适合你的模式“。 (请注意,ValueError消息并没有提到and因为numpy.array不知道是在问这个问题,而只是说实话。)

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

HTH,

例1:

这和操作员是如何工作的。

xy =>如果x是假的,那么x ,否则y

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

例2:

&运算符是一个按位和,如你所说。 按位操作仅适用于数字。 ab的结果是由ab中的1组成的数字。 例如:

 >>> 3 & 1 1 

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

 >>> 0b0011 & 0b0001 0b0001 

按位操作在概念上与布尔(真值)操作类似,但是它们仅在位上工作。

所以,给我几个关于我的车的声明

  1. 我的车是红色的
  2. 我的车有车轮

这两个陈述的逻辑“和”是:

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

至less我的车都是这样。 所以整个陈述的价值在逻辑上是正确的。

这两个陈述的“和”都是比较模糊的:

(“我的车是红色的”语句的数值)&(语句的数字值“我的车有车轮”)=>数字

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

示例3和4:

Numpy实现数组的算术运算 :

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

但是不对数组实施逻辑运算,因为你不能在Python中重载逻辑运算符 。 这就是为什么例子三不起作用,但例子四。

所以要回答你and vs &问题:使用and

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

然而,逻辑操作( andor not ),一直在使用。

  1. 在Python中, X and Y的expression式返回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不是一个通灵者,也不知道,你的意思是说[False, False]在逻辑expression式中, [False, False]应该等于True 。 在这里,它覆盖了一个标准的Python行为,即:“任何与len(collection) == 0空集合都是False ”。

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

有一个Python列表的操作在列表上进行list1 and list2将检查list1是否为空,如果是则返回list1如果不是则返回list2list1 + list2会将list1 + list2附加到list1 ,所以你得到一个新的列表len(list1) + len(list2)元素。

只有在应用元素方式时才有意义的运算符,如& ,将TypeError为元素运算,但不支持循环遍历元素。

Numpy数组支持元素操作。 array1 & array2将计算按位或array1array2每个对应的元素。 array1 + array2将计算array1array2每个对应元素的总和。

这不适用于andor

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

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

为此,你需要一个很好的bool(array1)定义。 对于在Python列表中使用的全局操作,定义如下: bool(list) == True如果list不为空,则为bool(list) == True如果为空,则为False 。 对于numpy的基于元素的操作,是否要检查是否有任何元素评估为True ,或者所有元素评估为True都有一些歧义。 因为两者都可以certificate是正确的,所以在数组上调用(间接) bool()时,numpy不会猜测并引发ValueError

对于第一个例子,并基于Django的文档
它总是会返回第二个列表,事实上,非空列表被视为Python的True值,因此python返回“last”的真值,所以第二个列表

 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]