【问题标题】:Is there a difference between "==" and "is"?“==”和“is”有区别吗?
【发布时间】:2010-09-13 01:50:47
【问题描述】:

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

【问题讨论】:

    标签: python reference equality semantics


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

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

      is 身份测试 == 相等性测试

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

      【讨论】:

        【解决方案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
        

        请同时查看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
        • 另一种展示差异的方法是比较不同类型的对象,当然,在使用== 时,这些对象永远不会是同一个对象,但仍然可以比较相等。例如5.0 是一个浮点值,而5 是一个整数。但5.0 == 5 仍将返回True,因为它们代表相同的值。在性能和鸭子类型方面,is 总是由解释器通过比较操作数的内存地址来测试,而== 则由对象决定它是否将自己定义为等于其他东西。跨度>
        • 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
        【解决方案4】:

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

        对象的身份一旦被创建就永远不会改变;你可以把它想象成对象在内存中的地址。

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

        【讨论】:

          【解决方案5】:

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

          【讨论】:

            【解决方案6】:

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

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

            【讨论】:

              【解决方案7】:

              有一个简单的经验法则告诉您何时使用==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 是这里有更强的比较)。否则,如果您只关心原语,通常== 就足够了。这更像是一条经验法则,当事情变得艰难时会被违反
              【解决方案8】:

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

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

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

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

              【讨论】:

                【解决方案9】:

                ==is 在 Python 中有区别吗?

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

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

                运算符 、==、>=、

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

                运算符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 风格指南也提到了two use-cases for is

                None 等单例的比较应始终使用isis not,绝不是相等运算符。

                另外,当你真正的意思是if x is not None时,请注意不要写if x -- 例如测试默认为None的变量或参数时 被设置为其他值。另一个值可能有一个类型(例如 作为容器)在布尔上下文中可能是错误的!

                从身份推断相等

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

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

                相等比较的默认行为(==!=)基于 对象的身份。因此,实例的相等比较 具有相同身份的结果是相等的,并且相等的比较 具有不同身份的实例会导致不平等。一种 这种默认行为的动机是希望所有对象 应该是自反的(即 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 的整数,此时它在生产中失败。

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

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

                【讨论】:

                • “根本不使用”也是一个很好的规则。惯用的is None 是一个例外,但那说== None 也可以...
                • @Jean-FrançoisFabre 另一个例外:official documentation 似乎建议使用is 来比较Enums。
                • 就是说两个自定义类比较,比如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?
                【解决方案10】:

                is== 有什么区别?

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

                • == 比较对象的值。
                • is 比较对象的引用。

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

                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 缓存(或者也许 reuses 会是更好的术语)某些对象,如小整数、一些字符串等。但这应该被视为 implementation detail 可以(即使不太可能)随时更改而不会发出警告。

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

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

                • 想要将某个值与Python constant 进行比较。 Python中的常量是:

                  • None
                  • True1
                  • False1
                  • NotImplemented
                  • Ellipsis
                  • __debug__
                  • 类(例如int is intint is 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 检查。如果您有相同的参考,它总是会比较只是

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

                因为__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 在 cmets 中提到的:

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

                就像 PEP8 提到的:

                不要使用 == 将布尔值与 TrueFalse 进行比较。

                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 进行检查在语义上是不正确的。我挑战你找到一个来源来支持你的断言 - 我认为你不会找到一个。
                • @AaronHall 是什么让您认为常量不是单例?请注意,只有NoneTrueFalse__debug__ 是您所说的“常量语义值”,因为它们不能被重新分配。但它们都是单例。
                • 阅读PEP 8 - Ctrl-F 并寻找“更糟”这个词。 - 如果你在进行单元测试,你会使用self.assertTrue
                • @AaronHall 在某些情况下,您确实需要is Trueif False 检查(但是是的,这些非常罕见 - 但如果您这样做,您可以 进行检查使用is)。这就是为什么有时甚至 CPython 也会使用它们(例如 herehere
                • 为什么is True== True 差? True is True ever 会失败吗?如果任何== True 更有可能失败,因为__eq__ 可以被覆盖为废话,但不能覆盖is
                【解决方案11】:

                由于本文中的其他人详细回答了==is 用于比较对象或变量的区别,我会强调主要是is 和@ 之间的比较987654325@ 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 解释器中。我希望它会有所帮助。
                【解决方案12】:

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

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

                上面的答案应该读作

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

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

                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)
                

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

                【讨论】:

                  【解决方案13】:

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

                  【讨论】:

                    【解决方案14】:

                    is 和 equals(==) 之间的 Python 区别

                    is 运算符可能看起来与相等运算符相同,但 它们不一样。

                    检查两个变量是否指向同一个对象,而 == 符号检查两个变量的值是否相同。

                    所以如果 is 运算符返回 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.
                    

                    【讨论】:

                    • 请仅对您从其他来源引用的文本使用块引号,此时您必须包含出处(请参阅stackoverflow.com/help/referencing)。如果这是您自己的文字,请删除块引号。
                    猜你喜欢
                    • 2022-02-04
                    • 1970-01-01
                    • 2011-04-16
                    • 1970-01-01
                    • 1970-01-01
                    • 2021-02-20
                    • 2023-03-27
                    相关资源
                    最近更新 更多