标签归档:boolean-expression

为什么“ a == b或c或d”总是评估为True?

问题:为什么“ a == b或c或d”总是评估为True?

我正在编写一个拒绝对未授权用户进行访问的安全系统。

import sys

print("Hello. Please enter your name:")
name = sys.stdin.readline().strip()
if name == "Kevin" or "Jon" or "Inbar":
    print("Access granted.")
else:
    print("Access denied.")

它可以按预期授予授权用户访问权限,但也允许未经授权的用户使用!

Hello. Please enter your name:
Bob
Access granted.

为什么会发生这种情况?我已经明确指出仅在name等于Kevin,Jon或Inbar 时才授予访问权限。我也尝试过相反的逻辑if "Kevin" or "Jon" or "Inbar" == name,但是结果是一样的。

I am writing a security system that denies access to unauthorized users.

import sys

print("Hello. Please enter your name:")
name = sys.stdin.readline().strip()
if name == "Kevin" or "Jon" or "Inbar":
    print("Access granted.")
else:
    print("Access denied.")

It grants access to authorized users as expected, but it also lets in unauthorized users!

Hello. Please enter your name:
Bob
Access granted.

Why does this occur? I’ve plainly stated to only grant access when name equals Kevin, Jon, or Inbar. I have also tried the opposite logic, if "Kevin" or "Jon" or "Inbar" == name, but the result is the same.


回答 0

在许多情况下,Python的外观和行为都像自然的英语,但这是这种抽象失败的一种情况。人们可以使用上下文线索来确定“ Jon”和“ Inbar”是与动词“ equals”连接的对象,但是Python解释器具有更多的字面意义。

if name == "Kevin" or "Jon" or "Inbar":

在逻辑上等效于:

if (name == "Kevin") or ("Jon") or ("Inbar"):

对于用户Bob而言,这等效于:

if (False) or ("Jon") or ("Inbar"):

or运营商选择以积极的第一个参数真值

if ("Jon"):

并且由于“ Jon”具有正的真值,因此if执行该块。这就是导致无论给定名称如何都将打印“授予访问权限”的原因。

所有这些推理也适用于表达式if "Kevin" or "Jon" or "Inbar" == name。第一个值,"Kevin"则为true,因此将if执行该块。


正确构造此条件有两种常用方法。

  1. 使用多个==运算符来显式检查每个值:
    if name == "Kevin" or name == "Jon" or name == "Inbar":

  2. 组成一个有效值序列,并使用in运算符测试成员资格:
    if name in {"Kevin", "Jon", "Inbar"}:

一般而言,第二个应该是首选,因为它更易于阅读,而且速度更快:

>>> import timeit
>>> timeit.timeit('name == "Kevin" or name == "Jon" or name == "Inbar"', setup="name='Inbar'")
0.4247764749999945
>>> timeit.timeit('name in {"Kevin", "Jon", "Inbar"}', setup="name='Inbar'")
0.18493307199999265

对于那些可能想要if a == b or c or d or e: ...如此解析的证据的人。内置ast模块提供了答案:

>>> import ast
>>> ast.parse("if a == b or c or d or e: ...")
<_ast.Module object at 0x1031ae6a0>
>>> ast.dump(_)
"Module(body=[If(test=BoolOp(op=Or(), values=[Compare(left=Name(id='a', ctx=Load()), ops=[Eq()], comparators=[Name(id='b', ctx=Load())]), Name(id='c', ctx=Load()), Name(id='d', ctx=Load()), Name(id='e', ctx=Load())]), body=[Expr(value=Ellipsis())], orelse=[])])"
>>>

因此test,该if语句的如下所示:

BoolOp(
 op=Or(),
 values=[
  Compare(
   left=Name(id='a', ctx=Load()),
   ops=[Eq()],
   comparators=[Name(id='b', ctx=Load())]
  ),
  Name(id='c', ctx=Load()),
  Name(id='d', ctx=Load()),
  Name(id='e', ctx=Load())
 ]
)

人们可以看到,它的布尔运算符or应用于多个values,即a == bcde

In many cases, Python looks and behaves like natural English, but this is one case where that abstraction fails. People can use context clues to determine that “Jon” and “Inbar” are objects joined to the verb “equals”, but the Python interpreter is more literal minded.

if name == "Kevin" or "Jon" or "Inbar":

is logically equivalent to:

if (name == "Kevin") or ("Jon") or ("Inbar"):

Which, for user Bob, is equivalent to:

if (False) or ("Jon") or ("Inbar"):

The or operator chooses the first argument with a positive truth value:

if ("Jon"):

And since “Jon” has a positive truth value, the if block executes. That is what causes “Access granted” to be printed regardless of the name given.

All of this reasoning also applies to the expression if "Kevin" or "Jon" or "Inbar" == name. the first value, "Kevin", is true, so the if block executes.


There are two common ways to properly construct this conditional.

  1. Use multiple == operators to explicitly check against each value:
    if name == "Kevin" or name == "Jon" or name == "Inbar":

  2. Compose a sequence of valid values, and use the in operator to test for membership:
    if name in {"Kevin", "Jon", "Inbar"}:

In general of the two the second should be preferred as it’s easier to read and also faster:

>>> import timeit
>>> timeit.timeit('name == "Kevin" or name == "Jon" or name == "Inbar"', setup="name='Inbar'")
0.4247764749999945
>>> timeit.timeit('name in {"Kevin", "Jon", "Inbar"}', setup="name='Inbar'")
0.18493307199999265

For those who may want proof that if a == b or c or d or e: ... is indeed parsed like this. The built-in ast module provides an answer:

>>> import ast
>>> ast.parse("if a == b or c or d or e: ...")
<_ast.Module object at 0x1031ae6a0>
>>> ast.dump(_)
"Module(body=[If(test=BoolOp(op=Or(), values=[Compare(left=Name(id='a', ctx=Load()), ops=[Eq()], comparators=[Name(id='b', ctx=Load())]), Name(id='c', ctx=Load()), Name(id='d', ctx=Load()), Name(id='e', ctx=Load())]), body=[Expr(value=Ellipsis())], orelse=[])])"
>>>

So the test of the if statement looks like this:

BoolOp(
 op=Or(),
 values=[
  Compare(
   left=Name(id='a', ctx=Load()),
   ops=[Eq()],
   comparators=[Name(id='b', ctx=Load())]
  ),
  Name(id='c', ctx=Load()),
  Name(id='d', ctx=Load()),
  Name(id='e', ctx=Load())
 ]
)

As one can see, it’s the boolean operator or applied to multiple values, namely, a == b and c, d, and e.


回答 1

简单的工程问题,让我们再简单一点。

In [1]: a,b,c,d=1,2,3,4
In [2]: a==b
Out[2]: False

但是,Python继承自语言C,因此将非零整数的逻辑值评估为True。

In [11]: if 3:
    ...:     print ("yey")
    ...:
yey

现在,Python建立在该逻辑的基础上,让您使用诸如或基于整数的逻辑文字。

In [9]: False or 3
Out[9]: 3

最后

In [4]: a==b or c or d
Out[4]: 3

编写它的正确方法是:

In [13]: if a in (b,c,d):
    ...:     print('Access granted')

为了安全起见,我还建议您不要对密码进行硬编码。

Simple engineering problem, let’s simply it a bit further.

In [1]: a,b,c,d=1,2,3,4
In [2]: a==b
Out[2]: False

But, inherited from the language C, Python evaluates the logical value of a non zero integer as True.

In [11]: if 3:
    ...:     print ("yey")
    ...:
yey

Now, Python builds on that logic and let you use logic literals such as or on integers, and so

In [9]: False or 3
Out[9]: 3

Finally

In [4]: a==b or c or d
Out[4]: 3

The proper way to write it would be:

In [13]: if a in (b,c,d):
    ...:     print('Access granted')

For safety I’d also suggest you don’t hard code passwords.


回答 2

有3个条件检查 if name == "Kevin" or "Jon" or "Inbar":

  • 名称==“凯文”
  • “乔恩”
  • “ Inbar”

这个if语句等效于

if name == "Kevin":
    print("Access granted.")
elif "Jon":
    print("Access granted.")
elif "Inbar":
    print("Access granted.")
else:
    print("Access denied.")

由于elif "Jon"将始终为真,因此授予对任何用户的访问权限


您可以使用以下任何一种方法

快速

if name in ["Kevin", "Jon", "Inbar"]:
    print("Access granted.")
else:
    print("Access denied.")

if name == "Kevin" or name == "Jon" or name == "Inbar":
    print("Access granted.")
else:
    print("Access denied.")

慢+不必要的代码

if name == "Kevin":
    print("Access granted.")
elif name == "Jon":
    print("Access granted.")
elif name == "Inbar":
    print("Access granted.")
else:
    print("Access denied.")

There are 3 condition checks in if name == "Kevin" or "Jon" or "Inbar":

  • name == “Kevin”
  • “Jon”
  • “Inbar”

and this if statement is equivalent to

if name == "Kevin":
    print("Access granted.")
elif "Jon":
    print("Access granted.")
elif "Inbar":
    print("Access granted.")
else:
    print("Access denied.")

Since elif "Jon" will always be true so access to any user is granted

Solution


You can use any one method below

Fast

if name in ["Kevin", "Jon", "Inbar"]:
    print("Access granted.")
else:
    print("Access denied.")

Slow

if name == "Kevin" or name == "Jon" or name == "Inbar":
    print("Access granted.")
else:
    print("Access denied.")

Slow + Unnecessary code

if name == "Kevin":
    print("Access granted.")
elif name == "Jon":
    print("Access granted.")
elif name == "Inbar":
    print("Access granted.")
else:
    print("Access denied.")

为什么`if None .__ eq __(“ a”)`似乎评估为True(但不完全)?

问题:为什么`if None .__ eq __(“ a”)`似乎评估为True(但不完全)?

如果您在Python 3.7中执行以下语句,它将(根据我的测试)打印b

if None.__eq__("a"):
    print("b")

但是,None.__eq__("a")计算为NotImplemented

当然,"a".__eq__("a")计算结果为True,并"b".__eq__("a")计算结果为False

我最初是在测试函数的返回值时发现此问题的,但是在第二种情况下却未返回任何内容-因此,该函数返回了None

这里发生了什么?

If you execute the following statement in Python 3.7, it will (from my testing) print b:

if None.__eq__("a"):
    print("b")

However, None.__eq__("a") evaluates to NotImplemented.

Naturally, "a".__eq__("a") evaluates to True, and "b".__eq__("a") evaluates to False.

I initially discovered this when testing the return value of a function, but didn’t return anything in the second case — so, the function returned None.

What’s going on here?


回答 0

这是一个很好的例子,说明为什么__dunder__不应该直接使用这些方法,因为它们通常不是等效操作符的适当替代;您应该使用==运算符来代替相等性比较,或者在这种特殊情况下,当检查时None,请使用is(跳至答案的底部以获取更多信息)。

你做完了

None.__eq__('a')
# NotImplemented

NotImplemented由于所比较的类型不同,返回的结果不同。考虑另一个示例,其中以这种方式比较了具有不同类型的两个对象,例如1'a'。这样做(1).__eq__('a')也不正确,并且会返回NotImplemented。比较这两个值是否相等的正确方法是

1 == 'a'
# False

这里发生的是

  1. 首先,(1).__eq__('a')尝试,然后返回NotImplemented。这表明不支持该操作,因此
  2. 'a'.__eq__(1)被调用,它也返回相同的NotImplemented。所以,
  3. 将对象视为不一样,然后False将其返回。

这是一个不错的小MCVE,它使用一些自定义类来说明这种情况:

class A:
    def __eq__(self, other):
        print('A.__eq__')
        return NotImplemented

class B:
    def __eq__(self, other):
        print('B.__eq__')
        return NotImplemented

class C:
    def __eq__(self, other):
        print('C.__eq__')
        return True

a = A()
b = B()
c = C()

print(a == b)
# A.__eq__
# B.__eq__
# False

print(a == c)
# A.__eq__
# C.__eq__
# True

print(c == a)
# C.__eq__
# True

当然,这并不能解释为什么该操作返回true。这是因为NotImplemented实际上是一个真实值:

bool(None.__eq__("a"))
# True

和…一样,

bool(NotImplemented)
# True

有关什么值被视为真实和虚假的更多信息,请参阅真值测试的文档部分以及此答案。值得注意的是,这里NotImplemented是truthy,但它会是一个不同的故事有类中定义一个__bool____len__方法返回False0分别。


如果要==使用与运算符等效的功能,请使用operator.eq

import operator
operator.eq(1, 'a')
# False

但是,如前所述,对于要检查的特定情况,请None使用is

var = 'a'
var is None
# False

var2 = None
var2 is None
# True

其功能等效项是使用operator.is_

operator.is_(var2, None)
# True

None是一个特殊对象,并且在任何时间内存中只有1个版本。IOW,它是NoneType该类的唯一单例(但是同一对象可以具有任意数量的引用)。该PEP8方针更加明确:

与单例之类的比较None应始终使用isis not,而不应使用相等运算符。

综上所述,对于单身人士喜欢None,与基准检查is是比较合适的,虽然两者==is会工作得很好。

This is a great example of why the __dunder__ methods should not be used directly as they are quite often not appropriate replacements for their equivalent operators; you should use the == operator instead for equality comparisons, or in this special case, when checking for None, use is (skip to the bottom of the answer for more information).

You’ve done

None.__eq__('a')
# NotImplemented

Which returns NotImplemented since the types being compared are different. Consider another example where two objects with different types are being compared in this fashion, such as 1 and 'a'. Doing (1).__eq__('a') is also not correct, and will return NotImplemented. The right way to compare these two values for equality would be

1 == 'a'
# False

What happens here is

  1. First, (1).__eq__('a') is tried, which returns NotImplemented. This indicates that the operation is not supported, so
  2. 'a'.__eq__(1) is called, which also returns the same NotImplemented. So,
  3. The objects are treated as if they are not the same, and False is returned.

Here’s a nice little MCVE using some custom classes to illustrate how this happens:

class A:
    def __eq__(self, other):
        print('A.__eq__')
        return NotImplemented

class B:
    def __eq__(self, other):
        print('B.__eq__')
        return NotImplemented

class C:
    def __eq__(self, other):
        print('C.__eq__')
        return True

a = A()
b = B()
c = C()

print(a == b)
# A.__eq__
# B.__eq__
# False

print(a == c)
# A.__eq__
# C.__eq__
# True

print(c == a)
# C.__eq__
# True

Of course, that doesn’t explain why the operation returns true. This is because NotImplemented is actually a truthy value:

bool(None.__eq__("a"))
# True

Same as,

bool(NotImplemented)
# True

For more information on what values are considered truthy and falsy, see the docs section on Truth Value Testing, as well as this answer. It is worth noting here that NotImplemented is truthy, but it would have been a different story had the class defined a __bool__ or __len__ method that returned False or 0 respectively.


If you want the functional equivalent of the == operator, use operator.eq:

import operator
operator.eq(1, 'a')
# False

However, as mentioned earlier, for this specific scenario, where you are checking for None, use is:

var = 'a'
var is None
# False

var2 = None
var2 is None
# True

The functional equivalent of this is using operator.is_:

operator.is_(var2, None)
# True

None is a special object, and only 1 version exists in memory at any point of time. IOW, it is the sole singleton of the NoneType class (but the same object may have any number of references). The PEP8 guidelines make this explicit:

Comparisons to singletons like None should always be done with is or is not, never the equality operators.

In summary, for singletons like None, a reference check with is is more appropriate, although both == and is will work just fine.


回答 1

您看到的结果是由于以下事实造成的:

None.__eq__("a") # evaluates to NotImplemented

评估为NotImplemented,其NotImplemented真实值记录为True

https://docs.python.org/3/library/constants.html

这应该由二进制特殊的方法被返回(如特殊的值__eq__()__lt__()__add__()__rsub__(),等等),以指示该操作不相对于另一种类型的实施; 可通过就地二进制特殊的方法(例如被返回__imul__()__iand__()为了相同的目的,等等)。它的真实价值是真实的。

如果您__eq()__手动调用该方法,而不仅仅是使用==,则需要准备好处理它可能返回NotImplemented并且其真实值是true 的可能性。

The result you are seeing is caused by that fact that

None.__eq__("a") # evaluates to NotImplemented

evaluates to NotImplemented, and NotImplemented‘s truth value is documented to be True:

https://docs.python.org/3/library/constants.html

Special value which should be returned by the binary special methods (e.g. __eq__(), __lt__(), __add__(), __rsub__(), etc.) to indicate that the operation is not implemented with respect to the other type; may be returned by the in-place binary special methods (e.g. __imul__(), __iand__(), etc.) for the same purpose. Its truth value is true.

If you call the __eq()__ method manually rather than just using ==, you need to be prepared to deal with the possibility it may return NotImplemented and that its truth value is true.


回答 2

正如您已经想过的None.__eq__("a")NotImplemented但是如果尝试类似

if NotImplemented:
    print("Yes")
else:
    print("No")

结果是

这意味着 NotImplemented true

因此,问题的结果显而易见:

None.__eq__(something) Yield NotImplemented

bool(NotImplemented)评估为True

所以if None.__eq__("a")永远是真的

As you already figured None.__eq__("a") evaluates to NotImplemented however if you try something like

if NotImplemented:
    print("Yes")
else:
    print("No")

the result is

yes

this mean that the truth value of NotImplemented true

Therefor the outcome of the question is obvious:

None.__eq__(something) yields NotImplemented

And bool(NotImplemented) evaluates to True

So if None.__eq__("a") is always True


回答 3

为什么?

它返回一个NotImplemented,是的:

>>> None.__eq__('a')
NotImplemented
>>> 

但是,如果您看一下:

>>> bool(NotImplemented)
True
>>> 

NotImplemented实际上是一个真实的值,所以这就是它返回的原因b,任何True会通过的东西,不会通过的东西False

怎么解决呢?

您必须检查它是否为True,因此请更加可疑,如下所示:

>>> NotImplemented == True
False
>>> 

所以你会做:

>>> if None.__eq__('a') == True:
    print('b')


>>> 

如您所见,它不会返回任何内容。

Why?

It returns a NotImplemented, yeah:

>>> None.__eq__('a')
NotImplemented
>>> 

But if you look at this:

>>> bool(NotImplemented)
True
>>> 

NotImplemented is actually a truthy value, so that’s why it returns b, anything that is True will pass, anything that is False wouldn’t.

How to solve it?

You have to check if it is True, so be more suspicious, as you see:

>>> NotImplemented == True
False
>>> 

So you would do:

>>> if None.__eq__('a') == True:
    print('b')


>>> 

And as you see, it wouldn’t return anything.


‘and’(布尔值)vs’&’(按位)-为什么列表与numpy数组在行为上有所不同?

问题:’and’(布尔值)vs’&’(按位)-为什么列表与numpy数组在行为上有所不同?

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

&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!

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

我阅读了有关按位运算的信息,以更好地理解该概念,但是我正在努力使用该信息来理解我上面的四个示例。

示例4使我达到了期望的输出,这很好,但是我仍然对何时/如何/为什么使用andvs 感到困惑&。为什么列表和NumPy数组在这些运算符上的行为不同?

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

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

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

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 answer and this answer helped me understand that and is a boolean operation but & is a bitwise operation.

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

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

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


回答 0

and测试两个表达式在逻辑上是否相符,True&(当与True/ False值一起使用时)测试两个表达式是否均在逻辑上True

在Python中,通常将空的内置对象在逻辑上视为,False而将非空的内置对象在逻辑上视为True。这可以简化常见的用例,在这种情况下,如果列表为空,则要执行某项操作;如果列表不为空,则要执行其他操作。注意,这意味着列表[False]在逻辑上是True

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

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

例如,列表2不能以位方式有意义地组合,因为它们可以包含任意不同的元素。可以按位组合的事物包括:对与错,整数。

相反,NumPy对象支持矢量化计算。也就是说,它们使您可以对多个数据执行相同的操作。

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

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

底线

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

  • 如果你有真值的载体,你想结合,使用numpy&

and tests whether both expressions are logically True while & (when used with True/False values) tests if both are True.

In Python, empty built-in objects are typically treated as logically False while 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:

>>> 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 and is 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.)

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.

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

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

Example 4 is simply a vectorized bit and operation.

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 numpy with &.


回答 1

关于 list

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

在普通的Python中,list它在任何方面都不是特殊的(除了具有可爱的构造语法,这主要是历史性的事故)。一旦创建了列表[3,2,6],它就具有所有意图和用途,只是一个普通的Python对象,例如number 3,set {3,7}或function lambda x: x+5

(是的,它支持更改其元素,并支持迭代和许多其他功能,但这只是类型的含义:它支持某些操作,而不支持其他一些操作。int支持提高幂,但不支持让它变得非常特别-这就是一个int是什么。lambda支持调用,但这并没有使其非常特别-这毕竟是lambda的目的:)。

关于 and

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

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

想象一下,Python解释“ a和b”(这种方式在字面上并没有发生,但有助于理解)。当涉及“和”时,它查看刚刚评估过的对象(a),并询问:您是真的吗?(不是:是吗True?)如果您是Class的作者,则可以自定义此答案。如果a答案为“否”,and(完全跳过b,则完全不评估,并且)说:a是我的结果(不是:我的结果是False)。

如果a没有回答,and请问:您的长度是多少?(再次,您可以将其自定义为a的类的作者)。如果a答案为0,and则执行与上述相同的操作-认为它为false(NOT False),跳过b并给出a结果。

如果a第二个问题的答案不是0(“您的长度是多少”),或者根本不回答,或者第一个问题的答案为“是”(“您是真的”),则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没想到任何定义它的明显方法。

麻木

另一方面:-D,numpy数组特殊的,或者至少是它们想要的。当然,numpy.array只是一个类,它不能and以任何方式覆盖,因此它做的第二件事是:当被问到“您是真的”时,numpy.array会引发ValueError,实际上是在说“请改正这个问题,我的真相视图不适合您的模型”。(请注意,ValueError消息并未and提及-因为numpy.array不知道是在问这个问题;它只是在谈论真相。)

对于&,这是完全不同的故事。numpy.array可以根据需要定义它,并且可以&与其他运算符一致地定义:逐点。这样您终于得到了想要的东西。

HTH,

About list

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

In ordinary Python, list is 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.

(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:).

About and

and is 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 and can (and must) do that.

The consequence of that is that and cannot be overloaded, just like for cannot be overloaded. It is completely general, and communicates through a specified protocol. What you can do is customize your part of the protocol, but that doesn’t mean you can alter the behavior of and completely. The protocol is:

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 a answers “no”, and (skips b completely, it is not evaluated at all, and) says: a is my result (NOT: False is my result).

If a doesn’t answer, and asks it: what is your length? (Again, you can customize this as an author of a‘s class). If a answers 0, and does the same as above – considers it false (NOT False), skips b, and gives a as result.

If a answers 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”), and evaluates b, and says: b is my result. Note that it does NOT ask b any questions.

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

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.

Putting those two together

Now I hope you understand your example 1. and doesn’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.

Second example: & on 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. int defines 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. list just doesn’t define it, probably because Guido didn’t think of any obvious way of defining it.

numpy

On the other leg:-D, numpy arrays are special, or at least they are trying to be. Of course, numpy.array is just a class, it cannot override and in 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 who is asking it the question; it just speaks about truth.)

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.

HTH,


回答 2

不能覆盖短路布尔运算符()andor因为没有令人满意的方法就可以做到这一点,而又不会引入新的语言功能或牺牲短路。如您所知,您可能不知道,他们评估第一个操作数的真值,并根据该值评估或返回第二个参数,或者不评估第二个参数而返回第一个:

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

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

定制其行为的唯一方法是重写__nonzero____bool__在Python 3中重命名为),因此您可以影响要返回的操作数,但不能返回其他值。当列表(和其他集合)根本不包含任何内容时,它们被定义为“真”,而当它们为空时,其定义为“假”。

NumPy数组拒绝该概念:对于它们针对的用例,两个不同的真理概念是相同的:(1)任何元素是否为真,以及(2)所有元素是否为真。由于这两个是完全(且无声地)不兼容的,而且都不是更正确或更普遍的,因此NumPy拒绝猜测并且要求您显式使用.any().all()

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

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:

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.

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().

& and | (and not, by the way) can be 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 - mylist2 doesn’t mean anything and mylist1 + mylist2 means something completely different, there is no & operator for lists.


回答 3

范例1:

运算符就是这样工作的。

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

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

范例2:

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

>>> 3 & 1
1

使用二进制文字(上面的数字相同)更容易看到正在发生的事情:

>>> 0b0011 & 0b0001
0b0001

按位运算在概念上与布尔(真)运算相似,但是它们仅对位有效。

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

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

这两个语句的逻辑“和”为:

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

至少对于我的车来说,这两者都是正确的。因此,该语句的整体值在逻辑上是正确的。

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

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

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

示例3和4:

Numpy实现数组的算术运算

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

但是不会为数组实现逻辑运算,因为您无法在python中重载逻辑运算符。这就是为什么示例三不起作用,但是示例四却不起作用的原因。

因此,回答您的andvs &问题:使用and

按位运算用于检查数字的结构(哪些位已设置,哪些位未设置)。这种信息主要用于底层操作系统接口(例如,unix许可位)。大多数python程序不需要知道这一点。

逻辑运算(andornot),然而,使用所有的时间。

Example 1:

This is how the and operator works.

x and y => if x is false, then x, else y

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

Example 2:

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

>>> 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

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 logically true.

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

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.

Example 3 and 4:

Numpy implements arithmetic operations for arrays:

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

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.

So to answer your and vs & question: Use 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.

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


回答 4

  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不是通灵的,它不知道您是否意味着例如在逻辑表达式中[False, False]应该等于True。在此方法中,它替代了标准的Python行为,即:“任何带有len(collection) == 0is的空集合False”。

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

  1. In Python an expression of X and Y returns Y, given that bool(X) == True or any of X or Y evaluate 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 True in a logical expression. In this it overrides a standard Python behaviour, which is: “Any empty collection with len(collection) == 0 is False“.

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


回答 5

对于第一个示例,基于Django的文档
,它将始终返回第二个列表,实际上非空列表被视为Python的True值,因此python返回“ last” 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]

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

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]

回答 6

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

仅在元素级应用时有意义的运算符(例如&)会引发一个TypeError,因为不支持在元素之间循环而不进行元素级操作。

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

这不适用于andor

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

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

为此,您需要对进行良好的定义bool(array1)。对于像在Python列表上使用的全局操作,其定义是bool(list) == Trueif list不为空,并且False为空。对于numpy的逐元素运算,是否要检查是否有任何元素求值为True,还是要检查所有元素的取值为,都存在一些歧义True。因为两者都可以说是正确的,所以numpy不会猜测并引发(间接)在数组上调用ValueErrorwhen的bool()情况。

Operations with a Python list operate on the list. list1 and list2 will check if list1 is empty, and return list1 if it is, and list2 if it isn’t. list1 + list2 will append list2 to list1, so you get a new list with len(list1) + len(list2) elements.

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.

Numpy arrays support element-wise operations. array1 & array2 will calculate the bitwise or for each corresponding element in array1 and array2. array1 + array2 will calculate the sum for each corresponding element in array1 and array2.

This does not work for and and or.

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

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) == True if list is not empty, and False if 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 ValueError when bool() is (indirectly) called on an array.


回答 7

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

假设“ mat”是一个numpy 5×5 2d数组,例如:

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]])

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

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

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

Suppose “mat” is a numpy 5×5 2d array such as:

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:

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

Python的`如果x不是None`或`如果x不是None`?

问题:Python的`如果x不是None`或`如果x不是None`?

我一直认为该if not x is None版本会更清晰,但是Google的样式指南PEP-8都使用if x is not None。是否存在任何微小的性能差异(我假设不是),并且在任何情况下确实不适合(使另一方成为我的会议的明显获胜者)吗?*

*我指的是任何单身人士,而不仅仅是None

…比较单例,如“无”。使用是或不是。

I’ve always thought of the if not x is None version to be more clear, but Google’s style guide and PEP-8 both use if x is not None. Is there any minor performance difference (I’m assuming not), and is there any case where one really doesn’t fit (making the other a clear winner for my convention)?*

*I’m referring to any singleton, rather than just None.

…to compare singletons like None. Use is or is not.


回答 0

没有性能差异,因为它们可以编译为相同的字节码:

Python 2.6.2 (r262:71600, Apr 15 2009, 07:20:39)
>>> import dis
>>> def f(x):
...    return x is not None
...
>>> dis.dis(f)
  2           0 LOAD_FAST                0 (x)
              3 LOAD_CONST               0 (None)
              6 COMPARE_OP               9 (is not)
              9 RETURN_VALUE
>>> def g(x):
...   return not x is None
...
>>> dis.dis(g)
  2           0 LOAD_FAST                0 (x)
              3 LOAD_CONST               0 (None)
              6 COMPARE_OP               9 (is not)
              9 RETURN_VALUE

从风格上讲,我尽量避免not x is y。尽管编译器总是将其视为not (x is y)。读者可能会误解为(not x) is y。如果我写的x is not y话就没有歧义。

There’s no performance difference, as they compile to the same bytecode:

Python 2.6.2 (r262:71600, Apr 15 2009, 07:20:39)
>>> import dis
>>> def f(x):
...    return x is not None
...
>>> dis.dis(f)
  2           0 LOAD_FAST                0 (x)
              3 LOAD_CONST               0 (None)
              6 COMPARE_OP               9 (is not)
              9 RETURN_VALUE
>>> def g(x):
...   return not x is None
...
>>> dis.dis(g)
  2           0 LOAD_FAST                0 (x)
              3 LOAD_CONST               0 (None)
              6 COMPARE_OP               9 (is not)
              9 RETURN_VALUE

Stylistically, I try to avoid not x is y. Although the compiler will always treat it as not (x is y), a human reader might misunderstand the construct as (not x) is y. If I write x is not y then there is no ambiguity.


回答 1

Google和Python的样式指南都是最佳做法:

if x is not None:
    # Do something about x

使用not x会导致不良结果。

见下文:

>>> x = 1
>>> not x
False
>>> x = [1]
>>> not x
False
>>> x = 0
>>> not x
True
>>> x = [0]         # You don't want to fall in this one.
>>> not x
False

您可能有兴趣了解对Python TrueFalse在Python 中评估了哪些文字:


编辑以下评论:

我只是做了一些测试。先not x is None不取反x,然后与相比较None。实际上,is使用这种方式时,似乎运算符具有更高的优先级:

>>> x
[0]
>>> not x is None
True
>>> not (x is None)
True
>>> (not x) is None
False

因此,not x is None以我的诚实观点,最好避免。


更多编辑:

我只是做了更多测试,可以确认bukzor的评论正确。(至少,我无法证明这一点。)

这意味着if x is not None结果与相同if not x is None。我站得住了。谢谢布克佐。

但是,我的答案仍然是:使用常规if x is not None:]

Both Google and Python‘s style guide is the best practice:

if x is not None:
    # Do something about x

Using not x can cause unwanted results.

See below:

>>> x = 1
>>> not x
False
>>> x = [1]
>>> not x
False
>>> x = 0
>>> not x
True
>>> x = [0]         # You don't want to fall in this one.
>>> not x
False

You may be interested to see what literals are evaluated to True or False in Python:


Edit for comment below:

I just did some more testing. not x is None doesn’t negate x first and then compared to None. In fact, it seems the is operator has a higher precedence when used that way:

>>> x
[0]
>>> not x is None
True
>>> not (x is None)
True
>>> (not x) is None
False

Therefore, not x is None is just, in my honest opinion, best avoided.


More edit:

I just did more testing and can confirm that bukzor’s comment is correct. (At least, I wasn’t able to prove it otherwise.)

This means if x is not None has the exact result as if not x is None. I stand corrected. Thanks bukzor.

However, my answer still stands: Use the conventional if x is not None. :]


回答 2

应该首先编写代码,以便程序员首先可以理解,然后再编译器或解释器理解。“不是”构造比“不是”更像英语。

Code should be written to be understandable to the programmer first, and the compiler or interpreter second. The “is not” construct resembles English more closely than “not is”.


回答 3

Python if x is not None还是if not x is None

TLDR:字节码编译器将它们都解析为x is not None-为了便于阅读,请使用if x is not None

可读性

我们之所以使用Python,是因为我们重视诸如人类可读性,可用性和各种编程范式的正确性之类的东西,而不是性能。

Python针对可读性进行了优化,尤其是在这种情况下。

解析和编译字节码

not 结合更弱is,所以这里没有逻辑的差异。请参阅文档

运算符isis not测试对象标识:x is y当且仅当x和y是同一对象时才为true。x is not y产生反真值。

is not有具体规定,在Python 语法作为语言可读性改善:

comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not'

因此,它也是语法的一个统一要素。

当然,它的解析方式不同:

>>> import ast
>>> ast.dump(ast.parse('x is not None').body[0].value)
"Compare(left=Name(id='x', ctx=Load()), ops=[IsNot()], comparators=[Name(id='None', ctx=Load())])"
>>> ast.dump(ast.parse('not x is None').body[0].value)
"UnaryOp(op=Not(), operand=Compare(left=Name(id='x', ctx=Load()), ops=[Is()], comparators=[Name(id='None', ctx=Load())]))"

但是字节编译器实际上会将转换not ... isis not

>>> import dis
>>> dis.dis(lambda x, y: x is not y)
  1           0 LOAD_FAST                0 (x)
              3 LOAD_FAST                1 (y)
              6 COMPARE_OP               9 (is not)
              9 RETURN_VALUE
>>> dis.dis(lambda x, y: not x is y)
  1           0 LOAD_FAST                0 (x)
              3 LOAD_FAST                1 (y)
              6 COMPARE_OP               9 (is not)
              9 RETURN_VALUE

因此,为了便于阅读并按预期使用语言,请使用is not

不使用它不明智的。

Python if x is not None or if not x is None?

TLDR: The bytecode compiler parses them both to x is not None – so for readability’s sake, use if x is not None.

Readability

We use Python because we value things like human readability, useability, and correctness of various paradigms of programming over performance.

Python optimizes for readability, especially in this context.

Parsing and Compiling the Bytecode

The not binds more weakly than is, so there is no logical difference here. See the documentation:

The operators is and is not test for object identity: x is y is true if and only if x and y are the same object. x is not y yields the inverse truth value.

The is not is specifically provided for in the Python grammar as a readability improvement for the language:

comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not'

And so it is a unitary element of the grammar as well.

Of course, it is not parsed the same:

>>> import ast
>>> ast.dump(ast.parse('x is not None').body[0].value)
"Compare(left=Name(id='x', ctx=Load()), ops=[IsNot()], comparators=[Name(id='None', ctx=Load())])"
>>> ast.dump(ast.parse('not x is None').body[0].value)
"UnaryOp(op=Not(), operand=Compare(left=Name(id='x', ctx=Load()), ops=[Is()], comparators=[Name(id='None', ctx=Load())]))"

But then the byte compiler will actually translate the not ... is to is not:

>>> import dis
>>> dis.dis(lambda x, y: x is not y)
  1           0 LOAD_FAST                0 (x)
              3 LOAD_FAST                1 (y)
              6 COMPARE_OP               9 (is not)
              9 RETURN_VALUE
>>> dis.dis(lambda x, y: not x is y)
  1           0 LOAD_FAST                0 (x)
              3 LOAD_FAST                1 (y)
              6 COMPARE_OP               9 (is not)
              9 RETURN_VALUE

So for the sake of readability and using the language as it was intended, please use is not.

To not use it is not wise.


回答 4

答案比人们做的要简单。

两种方法都没有技术优势,其他人都使用 “ x不是y” ,这显然是赢家。是否“看起来更像英语”并不重要;每个人都使用它,这意味着Python的每个用户-甚至是中国用户,其语言与Python看起来都不像-都将一目了然地理解它,稍稍不常见的语法将需要花费更多的脑力来解析。

至少在这个领域,不要仅仅为了与众不同而与众不同。

The answer is simpler than people are making it.

There’s no technical advantage either way, and “x is not y” is what everybody else uses, which makes it the clear winner. It doesn’t matter that it “looks more like English” or not; everyone uses it, which means every user of Python–even Chinese users, whose language Python looks nothing like–will understand it at a glance, where the slightly less common syntax will take a couple extra brain cycles to parse.

Don’t be different just for the sake of being different, at least in this field.


回答 5

is not由于is风格上的原因,操作员优先于否定结果。“ if x is not None:”的读法类似于英语,但“ if not x is None:”需要理解操作符的优先级,并且读起来并不像英文。

如果有性能上的差异,我会花钱is not,但这几乎肯定不是决定选择该技术的动机。显然,这将取决于实现。由于这is是不可替代的,因此无论如何都应该很容易优化任何区别。

The is not operator is preferred over negating the result of is for stylistic reasons. “if x is not None:” reads just like English, but “if not x is None:” requires understanding of the operator precedence and does not read like english.

If there is a performance difference my money is on is not, but this almost certainly isn’t the motivation for the decision to prefer that technique. It would obviously be implementation-dependent. Since is isn’t overridable, it should be easy to optimise out any distinction anyhow.


回答 6

我个人使用

if not (x is None):

每个程序员,即使不是Python语法专家的程序员,也都可以毫不歧义地立即理解它。

Personally, I use

if not (x is None):

which is understood immediately without ambiguity by every programmer, even those not expert in the Python syntax.


回答 7

if not x is None与其他编程语言更相似,但if x is not None对我来说绝对听起来更清晰(英语语法更正确)。

话虽如此,这似乎对我来说更偏爱。

if not x is None is more similar to other programming languages, but if x is not None definitely sounds more clear (and is more grammatically correct in English) to me.

That said it seems like it’s more of a preference thing to me.


回答 8

我更喜欢可读性强的形式,而x is not y 不是想如何最终写出运算符的代码处理优先级以产生可读性更高的代码。

I would prefer the more readable form x is not y than I would think how to eventually write the code handling precedence of the operators in order to produce much more readable code.