问题:“ ==”和“是”之间有区别吗?
我的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
进行测试以查看它们是否是同一对象?
回答 0
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
也请参阅此问题。
回答 1
有一条简单的经验法则可以告诉您何时使用==
或is
。
==
是为了价值平等。当您想知道两个对象是否具有相同的值时,请使用它。is
供参考平等。当您想知道两个引用是否引用同一对象时,请使用它。
通常,在将某事物与简单类型进行比较时,通常会检查值是否相等,因此应使用==
。例如,您的示例的目的可能是检查x是否具有等于2(==
)的值,而不是检查x
字面上是否指向与2相同的对象。
其他注意事项:由于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
:当您错误地将其用于值相等时,该行为应由实现决定。
回答 2
==
确定值是否相等,而is
确定它们是否是完全相同的对象。
回答 3
==
和is
Python 之间有区别吗?
是的,它们有非常重要的区别。
==
:检查是否相等-语义是等效对象(不一定是同一对象)将被测试为相等。如文档所述:
运算符<,>,==,> =,<=和!=比较两个对象的值。
is
:检查身份-语义是对象(保存在内存中)是对象。再次,文档说:
运算符
is
和is not
对象身份测试:x is y
当且仅当x
和y
是相同对象时,才为true 。使用该id()
功能确定对象身份。x is not y
产生反真值。
因此,对身份的检查与对对象ID的相等性检查相同。那是,
a is b
是相同的:
id(a) == id(b)
where id
是返回整数的内建函数,该整数“保证同时存在的对象之间是唯一的”(请参阅参考资料help(id)
),而where a
和b
则是任意对象。
其他使用说明
您应该将这些比较用于它们的语义。使用is
检查身份和==
检查平等。
因此,通常,我们使用is
来检查身份。当我们检查一个仅在内存中存在一次的对象(在文档中称为“单个”)时,这通常很有用。
用例is
包括:
None
- 枚举值(当使用枚举模块中的枚举时)
- 通常是模块
- 通常是由类定义产生的类对象
- 通常由函数定义产生的函数对象
- 在内存中应该只存在一次的所有其他内容(通常是所有单例)
- 您希望通过身份获得的特定对象
通常的用例==
包括:
- 数字,包括整数
- 弦
- 清单
- 套
- 词典
- 自定义可变对象
- 在大多数情况下,其他内置的不可变对象
一般使用情况下,再次对==
,就是你想可能不是对象相同的对象,相反,它可能是一个相当于一个
PEP 8方向
PEP 8,标准库的官方Python样式指南还提到了以下两个用例is
:
与单例之类的比较
None
应始终使用is
或is not
,而不应使用相等运算符。另外,当心
if x
您的意思if x is not None
,例如当测试是否将默认None
设置为的变量或参数设置为其他值时,请当心编写。另一个值可能具有在布尔上下文中可能为false的类型(例如容器)!
从身份推断平等
如果is
为true,通常可以推断出相等性-从逻辑上讲,如果对象是自身,则它应该测试为等同于自身。
在大多数情况下,此逻辑是正确的,但它依赖于__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)
相反,通常也是如此-如果某项测试的结果不相等,则通常可以推断出它们不是同一对象。
由于可以对相等性测试进行自定义,因此该推论并不总是适用于所有类型。
一个exceptions
一个显着的exceptions是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的整数为止,此时它在生产中失败了。
这是生产失败,可能已在代码审查中或可能通过样式检查器捕获。
让我强调一下:不要is
用于比较整数。
回答 4
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
什么时候使用?
通常,is
比较起来要快得多。这就是为什么CPython缓存(或者最好是重用)某些对象,例如小整数,某些字符串等。但是,这应该被视为实现细节,即使在没有警告的情况下也可以随时更改(即使可能性很小)。
您仅is
应在以下情况下使用:
- 想要检查两个对象是否真的是同一对象(不仅仅是相同的“值”)。一个示例可以是如果您使用单例对象作为常量。
想比较一个值和一个Python 常量。Python中的常量为:
None
True
1个False
1个NotImplemented
Ellipsis
__debug__
- 类(例如
int is int
或int is float
) - 内置模块或第三方模块中可能存在其他常量。例如
np.ma.masked
来自NumPy模块)
在其他所有情况下,您都应使用==
检查是否相等。
我可以自定义行为吗?
==
在其他答案中还没有提到某些方面:它是Python“ 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
检查。它总是会比较公正,如果你有相同的参考。
这些比较是否总是返回布尔值?
由于__eq__
可以重新实现或覆盖,因此不限于return 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正如亚伦·霍尔在评论中提到的那样:
通常,您不应该执行任何操作is True
或is False
检查,因为一个人通常在将条件隐式转换为布尔值的上下文中使用这些“检查” (例如,在if
语句中)。因此,进行is True
比较和隐式的布尔类型转换要比仅仅进行布尔类型转换做更多的工作-并且您将自己限制为布尔值(不认为它是pythonic)。
就像PEP8提到的那样:
不要将布尔值与
True
或False
使用进行比较==
。Yes: if greeting: No: if greeting == True: Worse: if greeting is True:
回答 5
他们是完全不同的。 is
检查对象身份,同时==
检查是否相等(一个概念取决于两个操作数的类型)。
幸运的巧合是“ is
”似乎可以正确地使用小整数(例如5 == 4 + 1)。那是因为CPython通过使整数成为单例来优化整数存储范围(-5到256)。此行为完全取决于实现,并且不能保证在所有较小的转换操作方式下都可以保留该行为。
例如,Python 3.5还使短字符串单身,但将它们切片会破坏此行为:
>>> "foo" + "bar" == "foobar"
True
>>> "foo" + "bar" is "foobar"
True
>>> "foo"[:] + "bar" == "foobar"
True
>>> "foo"[:] + "bar" is "foobar"
False
回答 6
https://docs.python.org/library/stdtypes.html#comparisons
is
身份
==
测试,是否相等
每个(小)整数值都映射到单个值,因此,每个3都是相同且相等的。这是实现细节,但不是语言规范的一部分
回答 7
您的回答是正确的。该is
运算符比较两个对象的身份。该==
操作比较两个对象的值。
一旦创建了对象,其身份就不会改变。您可能会认为它是对象在内存中的地址。
您可以通过定义__cmp__
方法或丰富的比较方法(例如)来控制对象值的比较行为__eq__
。
回答 8
看一下Stack Overflow问题,Python的“ is”运算符在使用整数时表现异常。
最主要的原因是“ is
”检查它们是否是同一对象,而不只是彼此相等(小于256的数字是特例)。
回答 9
简而言之,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
回答 10
正如John Feminella所说,大多数时候,您将使用==和!=,因为您的目标是比较值。我只想对剩下的时间做些什么:
NoneType只有一个实例,即None是一个单例。因此foo == None
与foo is None
意思相同。但是,is
测试速度更快,并且要使用Pythonic约定foo is None
。
如果您要对垃圾收集进行自省或处理,或者检查自定义构建的字符串实习小工具是否正常工作,则可能有一个用例foo
是is bar
。
True和False也是(现在)单例,但是没有用例,foo == True
也没有用例foo is True
。
回答 11
他们中的大多数人已经回答了这一点。正如补充说明(基于我的理解和实验,但不是来自书面记录)的声明
==如果变量引用的对象相等
从上面的答案应该理解为
==如果变量引用的对象相等并且属于相同类型/类的对象
。我根据以下测试得出了这个结论:
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)
这里的列表和元组的内容相同,但类型/类不同。
回答 12
is和equals(==)之间的Python区别
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
Tip: Avoid using is operator for immutable types such as strings and numbers, the result is unpredictable.
回答 13
当这篇文章中的其他人详细回答了这个问题时,我将主要强调字符串之间的比较is
以及可以给出不同结果的==
字符串,我敦促程序员谨慎使用它们。
为了进行字符串比较,请确保使用==
代替is
:
str = 'hello'
if (str is 'hello'):
print ('str is hello')
if (str == 'hello'):
print ('str == hello')
出:
str is hello
str == hello
但在下面的例子中==
,并is
会得到不同的结果:
str = 'hello sam'
if (str is 'hello sam'):
print ('str is hello sam')
if (str == 'hello sam'):
print ('str == hello sam')
出:
str == hello sam
结论:
is
谨慎使用以比较字符串