我的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
将返回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
请同时查看此问题.
有一个简单的经验法则告诉你何时使用==
或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
:当您错误地将其用于值相等时,行为将留给实现.
==
确定值是否相等,同时is
确定它们是否完全相同且相等.
Python
==
和is
Python 之间有区别吗?
是的,他们有非常重要的区别.
==
:检查是否相等 - 语义是等效对象(不一定是同一个对象)将测试相等.正如文件所说:
运算符<,>,==,> =,<=和!=比较两个对象的值.
is
:检查身份 - 语义是对象(在内存中保存)是对象.再次,文档说:
对象标识的运算符
is
和is not
测试:x is y
当且仅当x
和y
是同一个对象时才是真的.使用该id()
函数确定对象标识.x is not y
产生反向真值.
因此,检查身份与检查对象的ID是否相等是一样的.那是,
a is b
是相同的:
id(a) == id(b)
哪个id
是内置函数,它返回一个"保证在同时存在的对象中是唯一的"整数(参见参考资料help(id)
)以及任何对象的位置a
和b
位置.
您应该使用这些比较来表示它们的语义.使用is
检查身份和==
检查平等.
PEP 8是标准库的官方Python风格指南,还提到了两个用例is
:
与单身人士的比较
None
应始终使用is
或者is not
从不使用相等运算符.此外,
if x
当你真正想要时要小心写作if x is not None
- 例如,在测试默认的变量或参数是否None
设置为其他值时.另一个值可能有一个类型(如容器)在布尔上下文中可能为false!
如果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,包括)是Python中的单例,而不是检查相等性.
哇,这可能导致一些阴险的错误.我有一些代码检查a是否是b,这是我想要的,因为a和b通常是小数字.这个错误只发生在今天,经过六个月的生产,因为a和b最终足够大,不能被缓存. - gwg
它在开发中起作用.它可能已通过一些单元测试.
它在生产中起作用 - 直到代码检查大于256的整数,此时它在生产中失败.
这是一个生产故障,可能在代码审查中或可能与样式检查器中发生.
我要强调:不要is
用来比较整数.
它们完全不同. 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
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模块)
在其他每种情况下,您都应该使用它==
来检查是否相等.
==
在其他答案中已经有一些方面尚未提及:它是Pythons"数据模型"的一部分.这意味着可以使用该__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__
可以重新实现或覆盖,所以不限于返回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在评论中提到的:
通常,您不应该执行任何操作is True
或is False
检查,因为通常在上下文中使用这些"检查",隐式地将条件转换为布尔值(例如在if
语句中).因此,进行is True
比较和隐式布尔强制转换比仅仅进行布尔强制转换更多的工作 - 并且您将自己限制为布尔值(不被认为是pythonic).
像PEP8一样提到:
不要将布尔值与之比较
True
或False
使用==
.Yes: if greeting: No: if greeting == True: Worse: if greeting is True:
https://docs.python.org/library/stdtypes.html#comparisons
is
测试==
相等的身份
测试
每个(小)整数值都映射到一个值,因此每3个相同且相等.这是一个实现细节,但不是语言规范的一部分
你的答案是对的.该is
运算符比较两个对象的身份.该==
操作比较两个对象的值.
对象的标识一旦创建就永远不会改变; 您可能会将其视为内存中对象的地址.
您可以通过定义__cmp__
方法或丰富的比较方法来控制对象值的比较行为__eq__
.