Python中的字符串比较:is vs. ==

613
我注意到我正在编写的Python脚本行为异常,并将其追溯到一个无限循环,其中循环条件是 while line is not ''。通过调试器运行,结果发现line实际上是''。当我将其改为!=''而不是is not ''时,它正常工作了。
另外,即使比较int或Boolean值,一般认为使用'=='比使用'is'更好吗?我一直喜欢使用'is',因为我觉得它更美观和符合Python风格(这就是我陷入这个陷阱的原因...),但我想知道它是否仅用于在乎查找具有相同id的两个对象时。

3
这与你的经验相悖在哪里?NaN是唯一的内置反例;你只是误解了方向关系。规范中说:“对于所有内置Python对象(如字符串、列表、字典、函数等),如果x是y,则x == y也为True。”而不是“对于所有内置Python对象(如字符串、列表、字典、函数等),如果x == y,则x是y也为True。”由于某种原因,你假装它是后者。但实际上它不是。你看到了等号匹配,但实际上并不匹配。前面引用的语句完全允许这种情况的存在。 - codetaku
是的。我对那个问题的理解完全混乱了。我将其从问题中删除了,因为我认为它对未来的读者没有用处。 - Coquelicot
2
o1 is o2 => 比较o1和o2是否指向内存中的同一物理位置(换句话说,它们是同一个对象)。而o1 == o2 => 在这里,Python调用o1的__cmp__(o2)方法,理想情况下应该比较值并返回True或False。(换句话说,它比较值)对于Java人: 在Java中,使用str1 == str2来确定两个字符串变量是否引用相同的物理内存位置(称为对象标识,在Python中写作str1 is str2)。要比较Java中的字符串值,请使用str1.equals(str2);在Python中,请使用str1 == str2。 - Jadav Bheda
4个回答

667
对于所有内置的Python对象(如字符串,列表,字典,函数等),如果 x 是 y,则 x==y 也是 True。
并不总是如此。NaN 是一个反例。但通常情况下,标识(is)意味着相等(==)。反之则不成立:两个不同的对象可以具有相同的值。
另外,默认情况下使用“==”是否被普遍认为更好,即使比较int或Boolean值?
当比较值时使用“==”,当比较身份时使用“is”。
当比较整数(或不可变类型)时,你几乎总是想要前者。有一个优化让小整数可以用“is”进行比较,但不要依赖它。
对于布尔值,你不应该进行比较。不要这样写:
if x == True:
    # do something

写:

if x:
    # do something

None 进行比较时,is None 要优于 == None

我一直喜欢使用 'is',因为我觉得它更美观、更符合Python风格(这也是我陷入这个陷阱的原因...),但我想知道它是否只是被保留用于查找具有相同 ID 的两个对象。

是的,这正是它的用途。


4
@Coquelicot说:这样行不通,因为Python允许任何东西被用作布尔表达式。如果bool_a等于3且bool_b等于4,则bool_a!= bool_b,但bool_a异或bool_b为false(因为两个术语都是true)。 - dan04
4
@Mike说:"x是x"总是成立的。但这并不意味着"x == x"。NaN被定义为与自身不相等。 - dan04
3
关于速度问题,我认为在检查字符串是否被修改时(例如从re.sub返回的结果),将大字符串与“is”相等性比较而不是“==”,可能会更快。但经过 timeit 测试后发现仅有微不足道的 0.4% 速度提升。在我的情况下,不值得冒险去尝试,因为re.sub未来可能会改变这些字符串。 - estani
5
对于任何在以后几年查看此内容的人,这仍然适用于Python 3。 - RyPeck
2
@beauxq: 尝试 nan = float('nan'); nan is nan; nan == nan - dan04
显示剩余18条评论

281

我想展示一个关于不可变类型中 is== 如何运作的例子,请尝试以下代码:

a = 19998989890
b = 19998989889 +1
>>> a is b
False
>>> a == b
True

is用于比较两个对象在内存中的地址是否相同,==用于比较它们的值是否相等。例如,你可以看到Python会对小整数进行缓存:

c = 1
b = 1
>>> b is c
True

在比较值时应使用==,在比较身份时应使用is。(另外,从英语的角度来看,“equals”与“is”是不同的。)


6
另一个简单的例子,datetime.date.today() == datetime.date.today() 结果为 True,但是 datetime.date.today is datetime.date.today() 结果为 False。因为它们是等价的日期对象,但仍然是不同的对象。 - B Robster
5
你的建议忽略了一个危险的例子:str(None) is 'None' 的结果是 False,但 str(None) == 'None' 的结果是 True。请注意,翻译时需要保持原文意思不变,同时让翻译更加易懂。 - hobs
8
这是一个带有字符串的例子:x = 'foo'; y = 'bar'.replace('bar', 'foo'); (x is y) == False - ariddell
4
我喜欢的另一个例子是:'a'*50 == 'a'*50(返回True),而'a'*50 is 'a'*50(返回False)。 - Emre Sevinç

76
逻辑没有问题。该声明意为“如果x是y,则x==y也为真”,而不应该理解为“如果x==y,则x是y”。读者假设命题的反命题为真是一种逻辑错误。参见http://en.wikipedia.org/wiki/Converse_(logic)

1
@BrentHronik 这更与内存地址和对象的“id”有关,而不是实际逻辑。 - user3917838
如果x和y都是NaN,甚至具有相同的对象ID,第一条语句是否为真?在其他编程语言中(如C ++),NaN永远不等于它自己。 - Heather

27

查看此问题

你在理解的逻辑上存在一些问题。

对于所有内置的Python对象(如字符串、列表、字典、函数等),如果x is y,则x==y也为True。

这种说法略有误导。

如果使用is操作符,那么==操作符将为True,但反之不成立。==可能返回True,而is返回False。


“is” 意味着 == 只对内置类型才是必然成立的。一个人可以很容易地编写一个类,在该类中,对象本身并不相等。 - Mike Boers
通过说“如果is适用,则==将为True,但反之则不适用。”你只是陈述了OP所观察到的事实。 - user3917838

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接