122

is运算符不匹配变量的值,而是实例本身。

它的真正含义是什么?

我声明了两个变量x,并y在两个变量中分配了相同的值,但是当我使用is运算符时它返回 false。

我需要澄清一下。这是我的代码。

x = [1, 2, 3]
y = [1, 2, 3]

print(x is y)  # It prints false!
4

11 回答 11

201

您误解了is操作员的测试内容。它测试两个变量是否指向同一个对象,而不是两个变量是否具有相同的值。

is操作员的文档中:

对象身份的运算符is和测试:当且仅当和是同一个对象时为真。is notx is yxy

请改用==运算符:

print(x == y)

这打印Truex并且y是两个单独的列表:

x[0] = 4
print(y)  # prints [1, 2, 3]
print(x == y)   # prints False

如果您使用该id()功能,您将看到它xy具有不同的标识符:

>>> id(x)
4401064560
>>> id(y)
4401098192

但如果你要分配yx那么两者都指向同一个对象:

>>> x = y
>>> id(x)
4401064560
>>> id(y)
4401064560
>>> x is y
True

is显示两者是同一个对象,它返回True.

请记住,在 Python 中,名称只是引用值的标签;您可以有多个名称指向同一个对象。is告诉您两个名称是否指向同一个对象。==告诉您两个名称是否指代具有相同值的对象。

于 2012-11-30T17:40:23.050 回答
69

另一个重复的问题是为什么两个相等的字符串通常不相同,这里没有真正回答:

>>> x = 'a' 
>>> x += 'bc'
>>> y = 'abc'
>>> x == y
True
>>> x is y
False

那么,为什么它们不是同一个字符串?特别是考虑到这一点:

>>> z = 'abc'
>>> w = 'abc'
>>> z is w
True

让我们稍微推迟第二部分。第一个怎么可能是真的?

解释器必须有一个“实习表”,一个将字符串值映射到字符串对象的表,因此每次您尝试使用内容创建一个新字符串时'abc',都会返回相同的对象。维基百科对实习的工作方式进行了更详细的讨论。

Python一个字符串实习表;sys.intern您可以使用该方法手动实习字符串。

实际上,允许Python自动实习任何不可变类型,但不是必须这样做。不同的实现将实习不同的值。

CPython(如果您不知道您正在使用哪个实现,您正在使用的实现)自动实习小整数和一些特殊的单例,如False,但不是字符串(或大整数,或小元组,或其他任何东西)。你可以很容易地看到这一点:

>>> a = 0
>>> a += 1
>>> b = 1
>>> a is b
True
>>> a = False
>>> a = not a
>>> b = True
a is b
True
>>> a = 1000
>>> a += 1
>>> b = 1001
>>> a is b
False

好的,但为什么zw相同?

那不是解释器自动实习,而是编译器折叠值。

如果相同的编译时字符串在同一个模块中出现两次(这究竟意味着什么很难定义——它与字符串文字不同,因为r'abc', 'abc', 和'a' 'b' 'c'都是不同的文字但相同的字符串——但很容易理解直观地),编译器只会创建一个字符串实例,有两个引用。

事实上,编译器可以走得更远:'ab' + 'c'可以'abc'由优化器转换为,在这种情况下,它可以与一个'abc'常量一起折叠在同一个模块中。

同样,这是 Python 允许但不是必须做的事情。但在这种情况下,CPython 总是折叠小字符串(以及,例如,小元组)。(尽管交互式解释器的逐语句编译器不会运行与一次模块编译器相同的优化,因此您不会以交互方式看到完全相同的结果。)


那么,作为程序员,你应该怎么做呢?

嗯……没什么。您几乎没有任何理由关心两个不可变值是否相同。如果您想知道什么时候可以使用a is b而不是a == b,那您就问错问题了。a == b除非在两种情况下,否则总是使用:

  • 对于像x is None.
  • 对于可变值,当您需要知道变异是否x会影响y.
于 2014-09-10T05:38:57.873 回答
8

is仅当它们实际上是同一个对象时才返回 true。如果它们相同,则对其中一个的更改也会出现在另一个中。这是一个不同的例子。

>>> x = [1, 2, 3]
>>> y = [1, 2, 3]
>>> print x is y
False
>>> z = y
>>> print y is z
True
>>> print x is z
False
>>> y[0] = 5
>>> print z
[5, 2, 3]
于 2012-11-30T17:44:11.033 回答
8

在重复问题的提示下,这个类比可能有效:

# - Darling, I want some pudding!
# - There is some in the fridge.

pudding_to_eat = fridge_pudding
pudding_to_eat is fridge_pudding
# => True

# - Honey, what's with all the dirty dishes?
# - I wanted to eat pudding so I made some. Sorry about the mess, Darling.
# - But there was already some in the fridge.

pudding_to_eat = make_pudding(ingredients)
pudding_to_eat is fridge_pudding
# => False
于 2014-09-10T04:56:26.477 回答
6

isis not是 Python 中的两个恒等运算符。is运算符不比较变量的值,而是比较变量的身份。考虑一下:

>>> a = [1,2,3]
>>> b = [1,2,3]
>>> hex(id(a))
'0x1079b1440'
>>> hex(id(b))
'0x107960878'
>>> a is b
False
>>> a == b
True
>>>

a上面的示例向您展示了两个和的标识(也可以是 Cpython 中的内存地址)不同b(即使它们的值相同)。这就是为什么当您说a is b由于两个操作数的身份不匹配而返回 false 时。但是,当您说 时a == b,它返回 true,因为该==操作仅验证两个操作数是否具有相同的分配给它们的值。

有趣的例子(额外成绩):

>>> del a
>>> del b
>>> a = 132
>>> b = 132
>>> hex(id(a))
'0x7faa2b609738'
>>> hex(id(b))
'0x7faa2b609738'
>>> a is b
True
>>> a == b
True
>>>

在上面的示例中,即使ab是两个不同的变量,也a is b返回True. 这是因为类型aint不可变对象。所以python(我想是为了节省内存)b在创建它时分配了相同的对象以相同的值。所以在这种情况下,变量的身份匹配并且a is b结果是True

这将适用于所有不可变对象:

>>> del a
>>> del b
>>> a = "asd"
>>> b = "asd"
>>> hex(id(a))
'0x1079b05a8'
>>> hex(id(b))
'0x1079b05a8'
>>> a is b
True
>>> a == b
True
>>>

希望有帮助。

于 2015-12-03T01:42:55.667 回答
4

x is y与 相同id(x) == id(y),比较对象的身份。

正如@tomasz-kurgan 在下面的评论中指出的那样,is运算符对某些对象的行为异常。

例如

>>> class A(object):
...   def foo(self):
...     pass
... 
>>> a = A()
>>> a.foo is a.foo
False
>>> id(a.foo) == id(a.foo)
True

参考;
https://docs.python.org/2/reference/expressions.html#is-not
https://docs.python.org/2/reference/expressions.html#id24

于 2016-07-29T11:59:35.063 回答
3

你可以在这里检查一个小整数。257 以上的数字不是小的整数,所以它被计算为不同的对象。

==在这种情况下最好改用。

更多信息在这里:http ://docs.python.org/2/c-api/int.html

于 2012-11-30T17:42:40.800 回答
2

X 指向一个数组,Y 指向另一个数组。这些数组是相同的,但is操作员将查看那些不相同的指针。

于 2012-11-30T17:40:31.623 回答
1

它比较对象身份,即变量是否引用内存中的同一对象。这就像==在 Java 或 C 中(比较指针时)。

于 2012-11-30T17:41:35.523 回答
1

一个简单的水果例子

fruitlist = [" apple ", " banana ", " cherry ", " durian "]
newfruitlist = fruitlist
verynewfruitlist = fruitlist [:]
print ( fruitlist is newfruitlist )
print ( fruitlist is verynewfruitlist )
print ( newfruitlist is verynewfruitlist )

输出:

True
False
False

如果你试试

fruitlist = [" apple ", " banana ", " cherry ", " durian "]
newfruitlist = fruitlist
verynewfruitlist = fruitlist [:]
print ( fruitlist == newfruitlist )
print ( fruitlist == verynewfruitlist )
print ( newfruitlist == verynewfruitlist )

输出不同:

True
True
True

那是因为 == 运算符只比较变量的内容。要比较 2 个变量的身份,请使用is运算符

要打印识别号:

print ( id( variable ) )
于 2018-10-29T19:34:51.557 回答
-4

is运算符不过是英文版的==. 因为这两个列表的 ID 不同,所以答案是错误的。你可以试试:

a=[1,2,3]
b=a
print(b is a )#True

*因为两个列表的 ID 相同

于 2019-12-24T07:58:10.360 回答