ChatGPT解决这个技术问题 Extra ChatGPT

“==”和“is”有区别吗?

这个问题的答案是社区的努力。编辑现有答案以改进这篇文章。它目前不接受新的答案或交互。

我的 Google-fu 让我失望了。

在 Python 中,以下两个相等性测试是否等效?

n = 5
# Test one.
if n == 5:
    print 'Yay!'

# Test two.
if n is 5:
    print 'Yay!'

这是否适用于您将要比较实例的对象(例如 list)?

好的,所以这种回答我的问题:

L = []
L.append(1)
if L == [1]:
    print 'Yay!'
# Holds true, but...

if L is [1]:
    print 'Yay!'
# Doesn't.

所以 == 测试值,而 is 测试它们是否是同一个对象?


R
Rik Schoonbeek

如果两个变量指向同一个对象(在内存中),is 将返回 True,如果变量引用的对象相等,则返回 ==

>>> a = [1, 2, 3]
>>> b = a
>>> b is a 
True
>>> b == a
True

# Make a new copy of list `a` via the slice operator, 
# and assign it to variable `b`
>>> b = a[:] 
>>> b is a
False
>>> b == a
True

在您的情况下,第二个测试仅有效,因为 Python 缓存了小整数对象,这是一个实现细节。对于较大的整数,这不起作用:

>>> 1000 is 10**3
False
>>> 1000 == 10**3
True

字符串文字也是如此:

>>> "a" is "a"
True
>>> "aa" is "a" * 2
True
>>> x = "a"
>>> "aa" is x * 2
False
>>> "aa" is intern(x*2)
True

另请参阅this question


我发现:echo 'import sys;tt=sys.argv[1];print(tt is "foo", tt == "foo", id(tt)==id("foo"))'| python3 - foo 输出:False True False
您在 b = a[:] 切片运算符列表复制部分迷失了我,所以我编辑了您的答案以在那里发表评论。看起来我刚刚达到了在应用之前不必审查我的编辑的门槛,所以希望这对你来说很酷。无论如何,这里有一个有用的参考资料,说明如何复制我遇到的列表,并且必须参考才能弄清楚您在做什么:stackoverflow.com/a/2612815/4561887
1000 is 10**3 在 Python 3.7 中的计算结果为 True,因为 10**3 是类型 int。但 1000 is 1e3 的计算结果为 False,因为 1e3 是 float 类型。
@AhmedFasih 1000 is 10**3 是否为真取决于实现,并且取决于编译器预评估表达式 10**3x=10; 1000 is x**3 计算为 False
只是一个旁注。在比较 1000 is 10**3 之类的文字时,Python 3.8 及更高版本会返回 SyntaxWarning:SyntaxWarning: "is" with a literal. Did you mean "=="?
J
John Feminella

有一个简单的经验法则可以告诉您何时使用 ==is

== 用于价值平等。当您想知道两个对象是否具有相同的值时使用它。

is 是为了参考相等。当您想知道两个引用是否引用同一个对象时使用它。

通常,当您将某物与简单类型进行比较时,您通常会检查 值是否相等,因此您应该使用 ==。例如,您的示例的目的可能是检查 x 的值是否等于 2 (==),而不是 x 是否在字面上指的是与 2 相同的对象。

还有一点需要注意:由于 CPython 参考实现的工作方式,如果您错误地使用 is 来比较整数上的引用相等性,您将得到意想不到且不一致的结果:

>>> a = 500
>>> b = 500
>>> a == b
True
>>> a is b
False

这几乎是我们所期望的:ab 具有相同的值,但是是不同的实体。但是这个呢?

>>> c = 200
>>> d = 200
>>> c == d
True
>>> c is d
True

这与之前的结果不一致。这里发生了什么?事实证明,出于性能原因,Python 的参考实现将 -5..256 范围内的整数对象缓存为单例实例。下面是一个例子来证明这一点:

>>> for i in range(250, 260): a = i; print "%i: %s" % (i, a is int(str(i)));
... 
250: True
251: True
252: True
253: True
254: True
255: True
256: True
257: False
258: False
259: False

这是不使用 is 的另一个明显原因:当您错误地将其用于值相等时,该行为由实现决定。


关于 a=500b=500 的第一个示例,只是想指出,如果将 ab 设置为 [-5, 256] 之间的整数,a is b 实际上返回 True .更多信息在这里:stackoverflow.com/q/306313/7571052
@AsheKetchum,是的,请注意我写了“出于性能原因,Python 的参考实现将 -5..256 范围内的整数对象缓存为单例实例。”
就像在这里添加我的两个位。如果您想检查它是否是同一个对象,请使用 is(假设您有一个城市和路线对象列表;您可以比较位置,或者只检查它是否是同一个城市 - 所以 is 是这里有更强的比较)。否则,如果您只关心原语,通常 == 就足够了。这更像是一个经验法则,当事情变得艰难时会被违反
R
Russia Must Remove Putin

== 和 Python 中的 is 有区别吗?

是的,它们有一个非常重要的区别。

==:检查相等性 - 语义是等效对象(不一定是相同对象)将测试为相等。作为 documentation says

运算符 <、>、==、>=、<= 和 != 比较两个对象的值。

is:检查身份 - 语义是对象(保存在内存中)对象。同样,documentation says

运算符 is 和 is not 测试对象身份:当且仅当 x 和 y 是同一个对象时,x is y 为真。对象身份是使用 id() 函数确定的。 x is not y 产生逆真值。

因此,身份检查与检查对象 ID 的相等性相同。那是,

a is b

是相同的:

id(a) == id(b)

其中 id 是返回一个整数的内置函数,该整数“保证在同时存在的对象中是唯一的”(参见 help(id)),其中 ab 是任意对象。

其他使用说明

您应该将这些比较用于它们的语义。使用 is 检查身份,使用 == 检查相等性。

所以一般来说,我们使用 is 来检查身份。当我们检查一个只应该在内存中存在一次的对象时,这通常很有用,在文档中称为“单例”。

is 的用例包括:

没有任何

枚举值(使用 enum 模块中的枚举时)

通常是模块

通常是类定义产生的类对象

通常由函数定义产生的函数对象

任何其他应该只在内存中存在一次的东西(通常都是单例)

一个你想要的特定对象

== 的常用用例包括:

数字,包括整数

字符串

列表

字典

自定义可变对象

在大多数情况下,其他内置的不可变对象

同样,对于 ==,一般用例是您想要的对象可能不是 same 对象,而是可能是 等效 对象

PEP 8个方向

PEP 8,标准库的官方 Python 样式指南也提到了 two use-cases for is

与 None 之类的单例的比较应该始终使用 is 或 not 来完成,而不是相等运算符。此外,当您真正的意思是如果 x 不是 None 时,请注意编写 if x ——例如,在测试默认为 None 的变量或参数是否设置为其他值时。另一个值可能具有在布尔上下文中可能为假的类型(例如容器)!

从身份推断平等

如果 is 为真,则通常可以推断出相等性 - 从逻辑上讲,如果一个对象是它自己,那么它应该测试为等同于它自己。

在大多数情况下,此逻辑是正确的,但它依赖于 __eq__ 特殊方法的实现。正如 docs 所说,

相等比较(== 和 !=)的默认行为基于对象的标识。因此,具有相同身份的实例的相等比较导致相等,而具有不同身份的实例的相等比较导致不平等。这种默认行为的动机是希望所有对象都应该是自反的(即 x 是 y 意味着 x == y)。

并为保持一致性,建议:

平等比较应该是自反的。换句话说,相同的对象应该比较相等:x 是 y 意味着 x == y

我们可以看到这是自定义对象的默认行为:

>>> class Object(object): pass
>>> obj = Object()
>>> obj2 = Object()
>>> obj == obj, obj is obj
(True, True)
>>> obj == obj2, obj is obj2
(False, False)

反证词通常也是正确的——如果某些东西测试为不相等,您通常可以推断它们不是同一个对象。

由于可以自定义相等性测试,因此这种推断并不总是适用于所有类型。

一个例外

一个值得注意的例外是 nan - 它总是测试为不等于自身:

>>> nan = float('nan')
>>> nan
nan
>>> nan is nan
True
>>> nan == nan           # !!!!!
False

检查身份比检查相等(可能需要递归检查成员)要快得多。

但它不能代替相等,您可能会发现不止一个对象是等价的。

请注意,比较列表和元组的相等性将假定对象的身份相等(因为这是一种快速检查)。如果逻辑不一致 - 就像 nan 一样,这可能会产生矛盾:

>>> [nan] == [nan]
True
>>> (nan,) == (nan,)
True

一个警示故事:

问题是尝试使用 is 来比较整数。您不应假设整数的实例与通过另一个引用获得的实例相同。这个故事解释了原因。

一位评论者的代码依赖于小整数(-5 到 256 包括在内)在 Python 中是单例这一事实,而不是检查是否相等。

哇,这可能会导致一些阴险的错误。我有一些代码可以检查 a 是否为 b,因为 a 和 b 通常是很小的数字,所以可以按我的意愿工作。该错误仅在今天发生,经过六个月的生产,因为 a 和 b 终于大到不能被缓存。 – gwg

它在开发中起作用。它可能已经通过了一些单元测试。

它在生产中工作 - 直到代码检查大于 256 的整数,此时它在生产中失败。

这是一个生产失败,可能在代码审查或样式检查器中发现。

让我强调一下:do not use is to compare integers.


“根本不使用”也是一个很好的规则。惯用的 is None 是一个例外,但说 == None 也有效......
@Jean-FrançoisFabre 另一个例外:official documentation 似乎建议使用 is 来比较 Enum
这是否意味着两个自定义类比较,比如 a = Car("new"), B=Car("new"),如果我们使用 a==b,这等于 a is b,对吗?
@UniSize 我不认为你是对的。问题: 1. 你说 a 和 B,但是你说 a==b(小写)并且 Python 是区分大小写的。 2.您没有说 a 和 b 是否应该是等价的,但是具有相同参数的两个实例化暗示它们是等价的,但不是相同的对象,因此您的解释是错误的。请在此处重新阅读我的答案,让我知道缺少什么,并在您的回复中保持谨慎和明确。
@AaronHall 我的道歉,首先,这是一个错字。我修改了一下,a = Car("new"), b=Car("new"),如果我们用a==b,这是否等于a is b?我知道“is”是检查两个对象是否在同一个内存位置,a==b 是两个对象之间的比较。根据测试,a==b 返回 false,a is b 也返回 false。同样的初始化,为什么a==b会返回false呢?
N
Nicolas Gervais

== 确定值是否相等,而 is 确定它们是否是完全相同的对象。


C
Community

is 和 == 有什么区别?

==is 是不同的比较!正如其他人已经说过的那样:

== 比较对象的值。

是比较对象的引用。

在 Python 中,名称指代对象,例如在本例中 value1value2 指代存储值 1000int 实例:

value1 = 1000
value2 = value1

https://i.stack.imgur.com/WLzXy.png

因为 value2 引用同一个对象 is 并且 == 将给出 True

>>> value1 == value2
True
>>> value1 is value2
True

在以下示例中,名称 value1value2 引用不同的 int 实例,即使两者都存储相同的整数:

>>> value1 = 1000
>>> value2 = 1000

https://i.stack.imgur.com/IJgBI.png

因为存储相同的值(整数)== 将是 True,这就是为什么它通常被称为“值比较”。但是 is 将返回 False,因为它们是不同的对象:

>>> value1 == value2
True
>>> value1 is value2
False

什么时候用哪个?

通常 is 是一个更快的比较。这就是为什么 CPython 缓存(或者也许 reuses 会是更好的术语)某些对象,如小整数、一些字符串等。但这应该被视为 implementation detail 可以(即使不太可能)随时更改而不会发出警告。

您应该仅在以下情况下使用 is

想要检查两个对象是否真的是同一个对象(不仅仅是同一个“值”)。一个示例是,如果您使用单例对象作为常量。

想要将值与 Python 常量进行比较。 Python 中的常量是: None True1 False1 NotImplemented Ellipsis __debug__ 类(例如 int 是 int 或 int 是 float) 内置模块或 3rd 方模块中可能有其他常量。例如 NumPy 模块中的 np.ma.masked)

没有任何

真1

假1

未实现

省略

__调试__

类(例如 int 是 int 或 int 是 float)

内置模块或第 3 方模块中可能有额外的常量。例如 NumPy 模块中的 np.ma.masked)

所有其他情况下,您应该使用 == 来检查是否相等。

我可以自定义行为吗?

== 的某些方面在其他答案中尚未提及:它是 Pythons "Data model" 的一部分。这意味着可以使用 __eq__ 方法自定义其行为。例如:

class MyClass(object):
    def __init__(self, val):
        self._value = val

    def __eq__(self, other):
        print('__eq__ method called')
        try:
            return self._value == other._value
        except AttributeError:
            raise TypeError('Cannot compare {0} to objects of type {1}'
                            .format(type(self), type(other)))

这只是一个人为的例子来说明该方法是真正被调用的:

>>> MyClass(10) == MyClass(10)
__eq__ method called
True

请注意,默认情况下(如果在类或超类中找不到 __eq__ 的其他实现)__eq__ 使用 is

class AClass(object):
    def __init__(self, value):
        self._value = value

>>> a = AClass(10)
>>> b = AClass(10)
>>> a == b
False
>>> a == a

因此,如果您想要“更多”而不仅仅是自定义类的引用比较,那么实现 __eq__ 实际上很重要!

另一方面,您不能自定义 is 检查。如果您有相同的参考,它将始终比较 just

这些比较是否总是返回布尔值?

因为 __eq__ 可以重新实现或覆盖,所以不限于返回 TrueFalse。它可以返回任何东西(但在大多数情况下它应该返回一个布尔值!)。

例如,对于 NumPy 数组,== 将返回一个数组:

>>> import numpy as np
>>> np.arange(10) == 2
array([False, False,  True, False, False, False, False, False, False, False], dtype=bool)

is 检查将始终返回 TrueFalse

1 正如 Aaron Hall 在评论中提到的:

通常,您不应执行任何 is Trueis False 检查,因为通常在将 条件 隐式转换为布尔值的上下文中使用这些“检查”(例如在 if 语句中) )。因此,进行 is True 比较 隐式布尔转换比仅仅进行布尔转换所做的工作更多 - 并且您将自己限制为布尔值(不被视为 Pythonic)。

就像 PEP8 提到的:

不要使用 == 将布尔值与 True 或 False 进行比较。是:如果打招呼:否:如果打招呼 == 真:更糟:如果打招呼为真:


我将不得不不同意您将“常量”与 is 进行比较的断言 - 指向布尔值的名称应使用布尔上下文检查 - 例如 if __debug__:if not __debug__:。您永远不应该这样做 if __debug__ is True:if __debug__ == True: - 此外,常量只是一个常量语义值,而不是单例,因此在这种情况下使用 is 进行检查在语义上是不正确的。我挑战你找到一个来源来支持你的断言——我不认为你会找到一个。
@AaronHall 是什么让您认为常量不是单例?请注意,只有 NoneTrueFalse__debug__ 是您所谓的“常量语义值”,因为它们无法重新分配。但他们都是单身人士。
阅读 PEP 8 - Ctrl-F 并查找单词“worse”。 - 如果你在进行单元测试,你会使用 self.assertTrue
@AaronHall 在某些情况下,您确实需要 is Trueif False 检查(但是,这些是非常罕见的 - 但如果您这样做,您可以使用 is 进行检查)。这就是为什么有时甚至 CPython 也会使用它们(例如 herehere
为什么 is True== True 差? True is True永远会失败吗?如果任何 == True 更可能失败,因为 __eq__ 可以被覆盖为废话,但不能覆盖 is
D
Dan Lenski

它们完全不同is 检查对象身份,而 == 检查是否相等(取决于两个操作数类型的概念)。

is”似乎可以正确处理小整数(例如 5 == 4+1),这只是一个幸运的巧合。那是因为CPython optimizes the storage of integers in the range (-5 to 256) by making them singletons。这种行为完全依赖于实现,并且不能保证在所有形式的次要转换操作下都保持不变。

例如,Python 3.5 也使短字符串成为单例,但对它们进行切片会破坏这种行为:

>>> "foo" + "bar" == "foobar"
True
>>> "foo" + "bar" is "foobar"
True
>>> "foo"[:] + "bar" == "foobar"
True
>>> "foo"[:] + "bar" is "foobar"
False

t
twasbrillig

https://docs.python.org/library/stdtypes.html#comparisons

is 身份测试 == 平等测试

每个(小)整数值都映射到单个值,因此每 3 是相同且相等的。这是一个实现细节,不是语言规范的一部分


t
twasbrillig

你的答案是正确的。 is 运算符比较两个对象的身份。 == 运算符比较两个对象的值。

对象的身份一旦创建就永远不会改变;您可能会将其视为对象在内存中的地址。

您可以通过定义 __cmp__ 方法或 rich comparison 方法(如 __eq__)来控制对象值的比较行为。


C
Community

查看 Stack Overflow 问题Python's “is” operator behaves unexpectedly with integers

它主要归结为“is”检查它们是否是同一个对象,而不仅仅是彼此相等(256 以下的数字是一种特殊情况)。


s
suvojit_007

简而言之,is 检查两个引用是否指向同一个对象。== 检查两个对象是否具有相同的值。

a=[1,2,3]
b=a        #a and b point to the same object
c=list(a)  #c points to different object 

if a==b:
    print('#')   #output:#
if a is b:
    print('##')  #output:## 
if a==c:
    print('###') #output:## 
if a is c:
    print('####') #no output as c and a point to different object 

i
imanzabet

由于本文中的其他人详细回答了 ==is 用于比较对象或变量的区别的问题,我会强调主要是 is== 之间的比较 < strong>for 字符串 可以给出不同的结果,我会敦促程序员谨慎使用它们。

对于字符串比较,请确保使用 == 而不是 is

str = 'hello'
if (str is 'hello'):
    print ('str is hello')
if (str == 'hello'):
    print ('str == hello')

出去:

str is hello
str == hello

但是在下面的例子中 ==is 会得到不同的结果:

str2 = 'hello sam'
    if (str2 is 'hello sam'):
        print ('str2 is hello sam')
    if (str2 == 'hello sam'):
        print ('str2 == hello sam')

出去:

str2 == hello sam

结论与分析:

小心使用 is 比较字符串。由于 is 用于比较对象,并且在 Python 3+ 中,每个变量(例如字符串)都解释为对象,让我们看看上面段落中发生了什么。

在 python 中有 id 函数显示对象在其生命周期内的唯一常量。此 id 在 Python 解释器的后端使用 is 关键字比较两个对象。

str = 'hello'
id('hello')
> 140039832615152
id(str)
> 140039832615152

str2 = 'hello sam'
id('hello sam')
> 140039832615536
id(str2)
> 140039832615792

为什么 "is"" 对于带空格的字符串会这样工作?
根据先前的答案:似乎python对小整数和字符串执行缓存,这意味着它在此代码快照中使用相同的对象引用来处理“hello”字符串的出现,而它并没有为“hello sam”执行缓存,因为它是相对大于'hello'(即它管理'hello sam'字符串的不同引用,这就是为什么'is'运算符在后面的示例中返回false)如果我错了,请纠正我
@AkashGupta 抱歉延迟回复。我只是添加了更多解释为什么这件事发生在 Python 解释器中。我希望它会有所帮助。
我正在使用 Python 3.9 并且 str is 'hello' 抛出 SyntaxWarning: "is" with a literal. Did you mean "=="? 这告诉我们需要使用 == 进行字符串比较,这很方便。
J
John Machin

正如 John Feminella 所说,大多数时候您将使用 == 和 != 因为您的目标是比较值。我只想对你在剩下的时间里会做什么进行分类:

NoneType 只有一个实例,即 None 是单例。因此 foo == Nonefoo is None 的含义相同。然而,is 测试更快,Pythonic 约定是使用 foo is None

如果您正在做一些自省或处理垃圾收集或检查您的自定义字符串实习小工具是否正常工作等,那么您可能有一个 foo 的用例是 bar

True 和 False 也是(现在)单例,但没有 foo == True 的用例和 foo is True 的用例。


对于 foo=1foo==Truefoo is True 是不同的。
S
Sandeep

他们中的大多数人已经回答了这一点。就像一个附加说明(基于我的理解和实验,但不是来自记录的来源),声明

== 如果变量引用的对象相等

从上面的答案应该被理解为

== 如果变量引用的对象相等且对象属于同一类型/类

.我根据以下测试得出了这个结论:

list1 = [1,2,3,4]
tuple1 = (1,2,3,4)

print(list1)
print(tuple1)
print(id(list1))
print(id(tuple1))

print(list1 == tuple1)
print(list1 is tuple1)

这里列表和元组的内容相同,但类型/类不同。


P
Projesh Bhoumik

Python is 和 equals(==) 的区别

is 运算符可能看起来与相等运算符相同,但它们并不相同。 is 检查两个变量是否指向同一个对象,而 == 符号检查两个变量的值是否相同。因此,如果 is 运算符返回 True,则等式肯定为 True,但相反的结果可能为 True,也可能不是 True。

这是一个示例来演示相似性和差异。

>>> a = b = [1,2,3]
>>> c = [1,2,3]
>>> a == b
True
>>> a == c
True
>>> a is b
True
>>> a is c
False
>>> a = [1,2,3]
>>> b = [1,2]
>>> a == b
False
>>> a is b
False
>>> del a[2]
>>> a == b
True
>>> a is b
False

提示:避免对字符串和数字等不可变类型使用 is 运算符,结果不可预测。


请仅对您从其他来源引用的文本使用块引号,此时您必须包括出处(参见 stackoverflow.com/help/referencing)。如果这是您自己的文本,请删除块引号。