提问人:Bernard 提问时间:9/25/2008 最后编辑:martineauBernard 更新时间:2/4/2022 访问量:507798
“==”和“is”有区别吗?
Is there a difference between "==" and "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
答:
==
确定值是否相等,同时确定它们是否为完全相同的对象。is
https://docs.python.org/library/stdtypes.html#comparisons
is
身份测试 平等测试==
每个(小)整数值都映射到一个值,因此每 3 个值都是相同且相等的。这是一个实现细节,但不是语言规范的一部分
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
请同时查看此问题。
评论
echo 'import sys;tt=sys.argv[1];print(tt is "foo", tt == "foo", id(tt)==id("foo"))'| python3 - foo
False True False
b = a[:]
1000 is 10**3
在 Python 3.7 中计算为 True,因为 10**3 是类型。但计算结果为 False,因为 1e3 是类型。int
1000 is 1e3
float
1000 is 10**3
10**3
x=10; 1000 is x**3
False
SyntaxWarning: "is" with a literal. Did you mean "=="?
你的答案是正确的。运算符比较两个对象的标识。运算符比较两个对象的值。is
==
对象的标识一旦创建,就永远不会改变;您可以将其视为对象在内存中的地址。
您可以通过定义方法或丰富的比较方法(如 )来控制对象值的比较行为。__cmp__
__eq__
它们完全不同。 检查对象标识,同时检查是否相等(一个依赖于两个操作数类型的概念)。is
==
幸运的是,“”似乎可以正确地处理小整数(例如 5 == 4+1)。这是因为 CPython 通过使整数成为单例来优化整数(-5 到 256)范围内的存储。这种行为完全依赖于实现,不能保证在各种小的转换操作下都能得到保留。is
例如,Python 3.5 还将短字符串设置为单例,但对它们进行切片会破坏此行为:
>>> "foo" + "bar" == "foobar"
True
>>> "foo" + "bar" is "foobar"
True
>>> "foo"[:] + "bar" == "foobar"
True
>>> "foo"[:] + "bar" is "foobar"
False
看看 Stack Overflow 问题 Python 的“is”运算符在整数中表现得出乎意料。
它主要归结为“”检查它们是否是同一个对象,而不仅仅是彼此相等(低于 256 的数字是特例)。is
有一个简单的经验法则可以告诉您何时使用或 。==
is
==
是为了价值平等。当您想知道两个对象是否具有相同的值时,请使用它。is
供参考平等。当您想知道两个引用是否引用同一对象时,请使用它。
通常,当您将某些东西与简单类型进行比较时,通常会检查值是否相等,因此您应该使用 .例如,您的示例的目的可能是检查 x 的值是否等于 2 (),而不是从字面上引用是否与 2 相同的对象。==
==
x
还有一点需要注意:由于 CPython 引用实现的工作方式,如果您错误地用于比较整数的引用相等性,您将得到意外且不一致的结果:is
>>> a = 500
>>> b = 500
>>> a == b
True
>>> a is b
False
这几乎符合我们的预期:它们具有相同的价值,但却是不同的实体。但是这个呢?a
b
>>> 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=500
b=500
a
b
a is b
True
is
is
==
正如 John Feminella 所说,大多数时候你会使用 == 和 !=,因为你的目标是比较值。我只想对你剩下的时间会做什么进行分类:
NoneType 有一个且只有一个实例,即 None 是单例。因此和意思相同。但是,测试速度更快,Pythonic 约定是使用 .foo == None
foo is None
is
foo is None
如果你正在做一些反省或垃圾回收,或者检查你的定制字符串实习小工具是否正常工作或类似,那么你可能有一个用例。foo
bar
True 和 False 也是(现在)单例,但没有用例,也没有用例。foo == True
foo is True
评论
foo=1
foo==True
foo is True
和 在 Python 中有什么区别吗?
==
is
是的,它们有一个非常重要的区别。
==
:检查相等性 - 语义是等效对象(不一定是同一对象)将测试是否相等。正如文档所说:
运算符 <、>、==、>=、<= 和 != 比较两个对象的值。
IS
:检查身份 - 语义是对象(保存在内存中)是对象。同样,文档说:
运算符和对象标识测试:为 true 当且仅当 和 是同一个对象。对象标识是 使用函数确定。 产生相反的结果 真值。
is
is not
x is y
x
y
id()
x is not y
因此,标识检查与对象 ID 是否相等相同。那是
a is b
等同于:
id(a) == id(b)
其中 是返回一个整数的内置函数,该整数“保证在同时存在的对象中是唯一的”(请参阅),并且 where 和 是任意对象。id
help(id)
a
b
其他使用说明
您应该使用这些比较来了解它们的语义。用于检查身份和检查平等性。is
==
所以一般来说,我们用来检查身份。当我们检查一个在内存中只存在一次的对象时,这通常很有用,在文档中称为“单例”。is
用例包括:is
None
- 枚举值(使用枚举模块中的枚举时)
- 通常为模块
- 通常是由类定义生成的类对象
- 通常是函数定义产生的函数对象
- 内存中只应存在一次的任何其他内容(通常都是单例)
- 按标识所需的特定对象
通常的用例包括:==
- 数字,包括整数
- 字符串
- 列表
- 集
- 字典
- 自定义可变对象
- 大多数情况下,其他内置不可变对象
一般用例,同样,对于 ,是您想要的对象可能不是同一个对象,而可能是等效的对象==
PEP 8 个方向
PEP 8 是标准库的官方 Python 风格指南,也提到了两个用例:
与单例的比较应该始终使用 或 ,而不是相等运算符。
None
is
is not
另外,当你真正想写的时候要小心—— 例如,在测试默认为 的变量或参数是否设置为其他值时。另一个值可能具有类型(例如 作为容器),这在布尔上下文中可能是假的!
if x
if x is not None
None
从身份推断平等
如果为真,通常可以推断出相等性——从逻辑上讲,如果一个对象是它自己,那么它应该测试为等价于它自己。is
在大多数情况下,此逻辑是正确的,但它依赖于特殊方法的实现。正如文档所说,__eq__
相等比较 ( 和 ) 的默认行为基于 对象的标识。因此,实例的相等性比较 具有相同身份的结果是平等的,并且平等的比较 具有不同身份的实例会导致不平等。一个 这种默认行为的动机是希望所有对象 应该是反身的(即 x 是 y 意味着 x == y)。
==
!=
为了保持一致性,建议:
相等性比较应该是反身的。换句话说,相同 对象应比较相等:
x is 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(含 -5 到 256)在 Python 中是单例这一事实,而不是检查是否相等。
哇,这可能会导致一些阴险的错误。我有一些代码可以检查 a 是否是 b,它按我想要的方式工作,因为 a 和 b 通常是小数字。这个错误在生产六个月后才在今天发生,因为 a 和 b 终于大到无法缓存。– GWG公司
它在开发中起作用。它可能已经通过了一些单元测试。
它在生产中起作用 - 直到代码检查大于 256 的整数,此时它在生产中失败。
这是一个生产失败,可能在代码审查中被发现,或者可能在样式检查器中被捕获。
让我强调一下:不要用is
来比较整数。
评论
is None
== None
和 和有什么不一样?is
==
==
和不同的比较!正如其他人已经说过的:is
==
比较对象的值。is
比较对象的引用。
在Python中,名称引用对象,例如在本例中,并引用存储值的实例:value1
value2
int
1000
value1 = 1000
value2 = value1
因为指的是同一个对象,并且会给出:value2
is
==
True
>>> value1 == value2
True
>>> value1 is value2
True
在以下示例中,名称 和 引用不同的实例,即使两者都存储相同的整数:value1
value2
int
>>> value1 = 1000
>>> value2 = 1000
因为存储的相同值(整数)将是 ,这就是为什么它通常被称为“值比较”。但是会返回,因为这些是不同的对象:==
True
is
False
>>> value1 == value2
True
>>> value1 is value2
False
何时使用哪个?
一般来说,这是一个更快的比较。这就是为什么 CPython 缓存(或者重用会是更好的术语)某些对象(如小整数、某些字符串等)的原因。但这应该被视为实现细节,可以(即使不太可能)在没有警告的情况下随时更改。is
只有在以下情况下,才应使用 is
:
想要检查两个对象是否真的是同一个对象(而不仅仅是相同的“值”)。例如,如果使用单例对象作为常量。
想要将值与 Python 常量进行比较。Python 中的常量是:
None
True
1False
1NotImplemented
Ellipsis
__debug__
- 类(例如或
int is int
int is float
) - 内置模块或第三方模块中可能有其他常量。例如,来自 NumPy 模块的
np.马.masked
)
在所有其他情况下,您应该使用 ==
来检查是否相等。
我可以自定义行为吗?
在其他答案中没有提到某些方面:它是 Python“数据模型”的一部分。这意味着可以使用 __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
这些比较是否总是返回布尔值?
因为可以重新实现或覆盖,所以不限于 return 或 .它可以返回任何内容(但在大多数情况下,它应该返回一个布尔值!__eq__
True
False
例如,对于 NumPy 数组,将返回一个数组:==
>>> import numpy as np
>>> np.arange(10) == 2
array([False, False, True, False, False, False, False, False, False, False], dtype=bool)
但是支票总是会返回或!is
True
False
1 正如亚伦·霍尔(Aaron Hall)在评论中提到的:
通常,您不应该执行任何 OR 检查,因为通常在将条件隐式转换为布尔值的上下文中使用这些“检查”(例如在语句中)。因此,进行比较和隐式布尔强制转换比只执行布尔强制转换要做更多的工作 - 并且您将自己限制为布尔值(这不被认为是 pythonic)。is True
is False
if
is True
就像 PEP8 提到的那样:
不要将布尔值与 进行比较或使用 。
True
False
==
Yes: if greeting: No: if greeting == True: Worse: if greeting is True:
评论
is
if __debug__:
if not __debug__:
if __debug__ is True:
if __debug__ == True:
is
None
True
False
__debug__
is True
if False
is
)
is True
== True
True is True
== True
__eq__
is
由于这篇文章中的其他人详细回答了比较对象或变量之间的差异的问题,我主要强调字符串之间的比较,可以给出不同的结果,我会敦促程序员谨慎使用它们。==
is
is
==
对于字符串比较,请确保使用代替:==
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
结论与分析:
请小心比较字符串。
由于用于比较对象,并且在 Python 3+ 中每个变量(例如字符串)都解释为对象,因此让我们看看上面段落中发生了什么。is
is
在 python 中,有一个 id
函数,它显示对象在其生命周期内的唯一常量。此 id 在 Python 解释器的后端使用关键字比较两个对象。is
str = 'hello'
id('hello')
> 140039832615152
id(str)
> 140039832615152
但
str2 = 'hello sam'
id('hello sam')
> 140039832615536
id(str2)
> 140039832615792
评论
str is 'hello'
SyntaxWarning: "is" with a literal. Did you mean "=="?
==
他们中的大多数人已经回答了这一点。作为附加说明(基于我的理解和实验,但不是来自记录在案的来源),声明
== 如果变量引用的对象相等
从上面的答案应该读作
== 如果变量引用的对象相等且对象属于同一类型/类
.我根据以下测试得出了这个结论:
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)
在这里,列表和元组的内容相同,但类型/类不同。
简而言之,检查两个引用是否指向同一对象。 检查两个对象是否具有相同的值。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
评论