Python中 if foobar != None 和 if foobar is not None 是完全等价的吗?

有两个基础的问题,都有用过,不确定哪些场景完全等价 /不等价:

1. if foobar != None 和 if foobar is not None 是完全等价吗?
  1. if foobar is not None 和 if foobar 是完全等价吗?

Python中 if foobar != None 和 if foobar is not None 是完全等价的吗?
13 回复

都不等价


不完全等价。虽然两者在大多数情况下结果相同,但存在关键区别。

if foobar != None 使用的是 != 运算符,它会调用对象的 __ne__() 方法进行比较。这意味着,如果对象自定义了 __ne__() 方法,它可能会返回一个非预期的结果。例如,一个自定义类可以定义 __ne__(self, other) 方法,使得即使对象不是 None,与 None 比较时也返回 False

if foobar is not None 使用的是 is 运算符,它检查的是对象的身份(identity),即两个变量是否指向内存中的同一个对象。None 在 Python 中是一个单例对象,因此 isis not 是检查一个变量是否为 None最安全、最推荐的方法。

示例代码:

class WeirdObject:
    def __ne__(self, other):
        # 定义奇怪的不等行为:永远返回 False
        return False

obj = WeirdObject()

# 使用 != 检查
if obj != None:
    print("使用 !=: 对象不是 None") # 这行不会执行,因为 __ne__ 返回了 False
else:
    print("使用 !=: 对象是 None? (错误!)")

# 使用 is not 检查
if obj is not None:
    print("使用 is not: 对象不是 None (正确!)") # 这行会执行
else:
    print("使用 is not: 对象是 None")

输出:

使用 !=: 对象是 None? (错误!)
使用 is not: 对象不是 None (正确!)

总结:判断是否为 None 时,务必使用 isis not

不等,is,is not 好像是用来判断引用的对象是不是同一个,==,!=这种是判断值的

  1. 参考 https://stackoverflow.com/a/1504742
    2. if foobar 是判断真值,foobar=0 的时候 if foobar 也是 False

对于 None 来说,==和 is 应该没差别,语意上可能不一样,结果上应该是恒等的。

#4 重载 eq

先弄清 value 和 identity
value 可能会变,多个对象可以拥有相同的 value
identity 自对象创建到其被销毁都不会变,每一个对象的 identity 都不同,id(x)可以返回 x 对象的 identity
CPython 将 id(x)实现为返回存储对象的内存地址

is 测试两边运算对象的 id 是否相同,当且仅当对象 x 和 y 的 id(x) == id(y)时 is 返回 True
is not 返回与 is 相反的结果

!=, ==, >, <等叫做值比较,而值比较的默认行为可以通过修改__eq__,ne__等函数来改变

if 在一个对象的__bool
()不返回 False 和__len__()不返回 0 的情况下认定对象为真,还有,语言内置的常量 None 和 False 被认为是假的

1. if foobar != None 和 if foobar is not None 是完全等价吗?
在下面这种或与其类似的情况下是完全等价的:
class Hello:
def ne(self, other):
print(“Excalibur !”)
return (self is not other)

foobar = Hello()
print(foobar is not None)
print(foobar != None)
一般而言,是不完全等价的
因为 is not 测试 foobar 的 id 和 None 的 id 是否相同,而!=测试 foobar 的值和 None 的值是否相同

2. if foobar is not None 和 if foobar 是完全等价吗?
一般情况下是不等价的,因为前者测试 id 是否相同,后者测试 foobar 的__bool__()或__len__()
当然你也可以修改 foobar 的__bool__函数
以上结论基于 Python3.6 的官方文档^^/

说的是

楼上 说的很清楚了!

但是对于 None 来说有一点区别,你看很多 Python 代码就会发现:大部分情况下我们用 if foo is None 来做判断,因为 None 在 Python 中是一个全局唯一变量。官方文档中说:Since None is a singleton, testing for object identity (using == in C) is sufficient. 所以官方是推荐用 id 来 check 的。

即:None 只有一个,不存在值为 None 但是与 id(None) 不相等的情况。

写作 if foo != None 有点不 Pythonic (反正我是没这么见过哈哈哈)。

问题 2:

foo = 0
if foo 判断为假,
if foo is not None 判断为真。所以 is 判断的是 id 相同(对于 None 来说判断 id 相同和判断值相同没有太大区别,反正只有 1 个)。

所以二者是不一样的,除了 None 之外,文档( https://docs.python.org/3.6/library/stdtypes.html#truth-value-testing )还有下面的判断为假:

- constants defined to be false: None and False.
- zero of any numeric type: 0, 0.0, 0j, Decimal(0), Fraction(0, 1)
- empty sequences and collections: ‘’, (), [], {}, set(), range(0)

再啰嗦一点,对于不可变对象,为了避免重复创建,Python 做了驻留处理。比如下面代码:

>>> s1 = “ABC”
>>> s2 = “ABC”
>>> s1 is s2
True

但是我们实际比较二者的时候,应该用 s1 == s2。因为驻留操作是 CPython 的实现细节。副作用不应该被依赖。

贴两篇博客,有时间可以参考下:

《详解 Python 的 “==” 和 “ is ”》 https://www.kawabangga.com/posts/1673
《作用还是 Feature ?》 https://www.kawabangga.com/posts/2809

延伸阅读,True,1,1.0 分别作为字典的值的时候会怎样。

印象中 None null 这样的类型

不能用=

回到顶部