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指出,在我最初的例子中,我含糊不清,掩盖了我更深的困惑。 我已经更新了我的例子来澄清我的问题。
and
testing两个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
和&
。
短路布尔运算符( and
, or
)不能被覆盖,因为没有引入新的语言特性或牺牲短路,没有令人满意的方式来做到这一点。 你可能会也可能不知道,他们评估其真值的第一个操作数,并根据该值,计算并返回第二个参数,或者不评估第二个参数并返回第一个:
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:
这和操作员是如何工作的。
x和y =>如果x是假的,那么x ,否则y
换句话说,由于mylist1
不是False
,因此expression式的结果是mylist2
。 (只有空列表评估为False
。)
例2:
&
运算符是一个按位和,如你所说。 按位操作仅适用于数字。 a & b的结果是由a和b中的1组成的数字。 例如:
>>> 3 & 1 1
使用二进制文字 (与上面的数字相同)很容易看出发生了什么事情:
>>> 0b0011 & 0b0001 0b0001
按位操作在概念上与布尔(真值)操作类似,但是它们仅在位上工作。
所以,给我几个关于我的车的声明
- 我的车是红色的
- 我的车有车轮
这两个陈述的逻辑“和”是:
(是我的车红?)和(车有车轮?)=>虚假值的逻辑真
至less我的车都是这样。 所以整个陈述的价值在逻辑上是正确的。
这两个陈述的“和”都是比较模糊的:
(“我的车是红色的”语句的数值)&(语句的数字值“我的车有车轮”)=>数字
如果python知道如何将语句转换为数值,那么它会这样做,并计算两个值的位和。 这可能导致你相信&
可以互换,但是和上面的例子一样,它们是不同的东西。 另外,对于无法转换的对象,您只会得到一个TypeError
。
示例3和4:
Numpy实现数组的算术运算 :
ndarrays上的算术和比较操作被定义为元素操作,并且通常将ndarray对象作为结果。
但是不对数组实施逻辑运算,因为你不能在Python中重载逻辑运算符 。 这就是为什么例子三不起作用,但例子四。
所以要回答你and
vs &
问题:使用and
。
按位操作用于检查数字的结构(哪些位被设置,哪些位未被设置)。 这种信息主要用于低级操作系统接口(例如unix权限位 )。 大多数python程序不需要知道这一点。
然而,逻辑操作( and
, or
not
),一直在使用。
-
在Python中,
X and Y
的expression式返回Y
,假设bool(X) == True
或者X
或Y
任何一个计算为False,例如:True and 20 >>> 20 False and 20 >>> False 20 and [] >>> []
-
按位运算符只是没有为列表定义。 但它被定义为整数 – 操作数字的二进制表示。 考虑16(01000)和31(11111):
16 & 31 >>> 16
-
NumPy不是一个通灵者,也不知道,你的意思是说
[False, False]
在逻辑expression式中,[False, False]
应该等于True
。 在这里,它覆盖了一个标准的Python行为,即:“任何与len(collection) == 0
空集合都是False
”。 -
可能是NumPy数组&操作符的预期行为。
有一个Python列表的操作在列表上进行 。 list1 and list2
将检查list1
是否为空,如果是则返回list1
如果不是则返回list2
。 list1 + list2
会将list1 + list2
附加到list1
,所以你得到一个新的列表len(list1) + len(list2)
元素。
只有在应用元素方式时才有意义的运算符,如&
,将TypeError
为元素运算,但不支持循环遍历元素。
Numpy数组支持元素操作。 array1 & array2
将计算按位或array1
和array2
每个对应的元素。 array1 + array2
将计算array1
和array2
每个对应元素的总和。
这不适用于and
和or
。
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]