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

rys*_*qui 124 python bit-manipulation numpy boolean-expression ampersand

是什么解释了列表与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 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!
Run Code Online (Sandbox Code Playgroud)

这个答案和这个答案都帮助我理解'和'是一个布尔运算,但'&'是一个按位运算.

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

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

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!
Run Code Online (Sandbox Code Playgroud)

上面的例子4让我得到了我想要的输出,所以没关系.

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

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

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

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!
Run Code Online (Sandbox Code Playgroud)

EDITS

1)感谢@delnan指出,在我最初的例子中,我的模糊性掩盖了我更深层次的困惑.我已经更新了我的例子以澄清我的问题.

ram*_*gal 98

and测试两个表达式是否在逻辑上True同时&(当用于True/ False值)测试如果两者都True.

在Python中,空内置对象通常被视为逻辑上False,而非空内置对象在逻辑上True.这有助于您希望在列表为空时执行某些操作的常见用例,如果列表不是,则可以执行其他操作.请注意,这意味着列表[False]在逻辑上True:

>>> if [False]:
...    print 'True'
...
True
Run Code Online (Sandbox Code Playgroud)

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

例如,列表不能有意义地以按位方式组合,因为它们可以包含任意不同的元素.可以按位组合的东西包括:真实和法尔斯,整数.

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

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

例4只是矢量化位and操作.

底线

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

  • 如果您有要合并真值向量,使用numpy&.


小智 19

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

something_true and x -> x
something_false and x -> something_false
something_true or x -> something_true
something_false or x -> x
Run Code Online (Sandbox Code Playgroud)

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

自定义其行为的唯一方法是覆盖__nonzero__(__bool__在Python 3中重命名),这样您可以影响返回哪个操作数,但不返回不同的操作.列表(和其他集合)在它们包含任何内容时被定义为"真实",并且在它们为空时被定义为"虚假".

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

&|(not顺便说一下)可以完全覆盖,因为它们不会短路.它们可以在重写时返回任何内容,并且NumPy充分利用它来执行元素操作,就像它们几乎任何其他标量操作一样.另一方面,列表不会在其元素之间广播操作.正如mylist1 - mylist2没有任何意义和mylist1 + mylist2意味着完全不同的东西,没有&列表的运算符.

  • 这可以产生的一个特别有趣的例子是`[False]或[True]`求值为`[False]`,`[False]和[True]`求值为`[True]`. (3认同)

Vek*_*eky 16

关于 list

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

在普通的Python中,list任何方式都不是特别的(除了具有可爱的构造语法,这主要是历史事故).一旦创建了一个列表[3,2,6],它就是一个普通的Python对象,如数字3,集合{3,7}或函数lambda x: x+5.

(是的,它支持更改其元素,它支持迭代,以及许多其他事情,但这只是一种类型:它支持一些操作,而不支持其他一些.int支持提升功率,但这不支持使它非常特殊 - 它就是一个int.lambda支持调用,但这并不会使它非常特殊 - 毕竟这就是lambda的用途:).

关于 and

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

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

想象一下Python解释"a和b"(这不是以字面意思发生的,但它有助于理解).当涉及到"和"时,它会查看它刚评估过的对象(a),然后问:你是真的吗?(不是:你True呢?)如果你是一个班级的作者,你可以自定义这个答案.如果a答案为"否",and(完全跳过b,根本不进行评估,并且)说:a是我的结果(NOT:False是我的结果).

如果a没有回答,and请问:你的长度是多少?(同样,您可以将其定制为作为a班级的作者).如果a答案0,and与上面相同 - 认为它是假(假),跳过b,并给出a结果.

如果a回答第二个问题("你的长度是多少")以外的其他东西,或者它根本没有回答,或者它对第一个回答"是"("你是真的"),则and评估b,并且说:b是我的结果.请注意,它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的元素无关 - 它们不会在任何地方输入图片.

第二个例子:&list

另一方面,&操作员就像任何其他操作员一样+,例如.可以通过在该类上定义特殊方法来为类型定义它.int将它定义为按位"和",bool将其定义为逻辑"和",但这只是一个选项:例如,集合和其他一些对象(如dict键视图)将其定义为集合交集.list只是没有定义它,可能是因为Guido没有想到任何明显的方法来定义它.

numpy的

在另一条腿:-D,numpy数组特殊的,或者至少他们试图成为.当然,numpy.array只是一个类,它不能and以任何方式覆盖,所以它做了下一个最好的事情:当被问到"你是不是真的"时,numpy.array提出了一个ValueError,有效地说"请重新解释这个问题,我的真相的观点不适合你的模型".(注意,ValueError消息没有and提及 - 因为numpy.array不知道是在问这个问题;它只是讲真话.)

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

HTH,


Set*_*eth 14

例1:

这就是运营商的工作方式.

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

换句话说,既然mylist1不是False,表达式的结果就是mylist2.(只有空列表评估为False.)

例2:

&正如你所提到的那样,操作员是按位的.按位运算仅适用于数字.a&b的结果是由1位组成的数字,在ab中均为1 .例如:

>>> 3 & 1
1
Run Code Online (Sandbox Code Playgroud)

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

>>> 0b0011 & 0b0001
0b0001
Run Code Online (Sandbox Code Playgroud)

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

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

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

这两个陈述的逻辑"和"是:

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

至少对于我的车而言,两者都是真的.因此,整个声明的价值在逻辑上是正确的.

这两个陈述的按位"和"有点模糊:

(声明'我的车是红色'的数字值)&(声明'我的车有轮子'的数字值)=>数字

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

例3和4:

Numpy 为数组实现算术运算:

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

但是没有为数组实现逻辑运算,因为你不能在python中重载逻辑运算符.这就是为什么示例三不起作用,但示例四的确如此.

因此,要回答你的andVS &问题:使用and.

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

逻辑运算(and,or,not),然而,使用所有的时间.


Zau*_*bov 11

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

    True and 20 
    >>> 20
    
    False and 20
    >>> False
    
    20 and []
    >>> []
    
    Run Code Online (Sandbox Code Playgroud)
  2. 仅为列表定义了按位运算符.但它是为整数定义的 - 操作数字的二进制表示.考虑16(01000)和31(11111):

    16 & 31
    >>> 16
    
    Run Code Online (Sandbox Code Playgroud)
  3. NumPy不是一个通灵者,它不知道,你是否意味着例如在逻辑表达式中[False, False]应该相等True.在此,它会覆盖标准的Python行为,即:"任何空集合len(collection) == 0都是False".

  4. 可能是NumPy阵列和运营商的预期行为.