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

2024-11-18 08:40:00
admin
原创
12
摘要:问题描述:我的Google-fu让我失望了。在 Python 中,以下两个相等性测试是否等效?n = 5 # Test one. if n == 5: print 'Yay!' # Test two. if n is 5: print 'Yay!' 对于您要比较实例(说一下)的对象来说,这是...

问题描述:

我的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测试以查看它们是否是同一个对象?


解决方案 1:

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

也请看一下这个问题。

解决方案 2:

有一个简单的经验法则可以告诉您何时使用==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:当您错误地将其用于值相等时,行为就留给实现。

解决方案 3:

==Python 中的和有区别吗is

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

==:检查相等性 - 语义是等效对象(不一定是同一个对象)将测试为相等。正如文档所述:

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

is:检查身份 - 语义是对象(保存在内存中)就是对象。同样,文档中说:

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

因此,身份检查与对象 ID 是否相等相同。也就是说,

a is b

与以下相同:

id(a) == id(b)

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

其他使用说明

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

因此,我们通常用它is来检查身份。这通常在我们检查内存中只应存在一次的对象时很有用,在文档中称为“单例”。

用例is包括:

  • None

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

  • 通常是模块

  • 通常由类定义产生的类对象

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

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

  • 根据身份获取特定对象

通常的用例==包括:

  • 数字,包括整数

  • 字符串

  • 列表

  • 字典

  • 自定义可变对象

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

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

PEP 8 方向

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来比较整数。

解决方案 4:

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

解决方案 5:

is和有什么区别==

==并且is是不同的比较!正如其他人所说:

  • ==比较对象的值。

  • is比较对象的引用。

在 Python 中,名称指的是对象,例如在这种情况下value1value2指的是int存储值的实例1000

value1 = 1000
value2 = value1

在此处输入图片描述

因为value2指的是同一个对象is,所以==会给出True

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

在以下示例中,名称value1value2引用不同的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 的“数据模型”的一部分。这意味着可以使用该方法定制其行为__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__可以重新实现或覆盖,所以它不限于返回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 True或检查,因为人们通常在将条件is False隐式转换为布尔值的上下文中使用这些“检查” (例如在语句中)。因此,进行比较隐式布尔转换比仅进行布尔转换要多得多 - 并且您将自己限制为布尔值(这不被认为是 Pythonic)。if`is True`

正如 PEP8 所提到的:

不要使用 将布尔值与True或进行比较。False`==`

Yes:   if greeting:
No:    if greeting == True:
Worse: if greeting is True:

解决方案 6:

它们完全不同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

解决方案 7:

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

is身份测试
==平等测​​试

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

解决方案 8:

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

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

__cmp__您可以通过定义方法或丰富的比较方法来控制对象值的比较行为__eq__

解决方案 9:

看一下 Stack Overflow 上的问题Python 的“is”运算符对整数的行为异常

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

解决方案 10:

简而言之,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 

解决方案 11:

由于这篇文章中的其他人详细回答了比较对象或变量时==和之间的区别的问题,我主要强调字符串的和之间的比较,因为它们会产生不同的结果,我敦促程序员谨慎使用它们。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

结论与分析:

谨慎使用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

解决方案 12:

正如 John Feminella 所说,大多数时候你会使用 == 和 !=,因为你的目标是比较值。我只想分类一下你其余时间会做的事情:

NoneType 有且只有一个实例,即 None 是单例。因此foo == Nonefoo is None含义相同。但是is测试速度更快,并且 Pythonic 惯例是使用foo is None

如果您正在进行一些内省或处理垃圾收集或检查您定制的字符串驻留小工具是否正常工作或诸如此类的事情,那么您可能有一个使用foois的用例bar

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

解决方案 13:

他们中的大多数人已经回答了这个问题。作为补充说明(基于我的理解和实验,但不是来自文献资料),声明

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

上面的答案应该理解为

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

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

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)

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

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用