is 运算符不匹配变量的值,而是实例本身。
它的真正含义是什么?
我声明了两个名为 x
和 y
的变量,在这两个变量中分配了相同的值,但是当我使用 is
运算符时它返回 false。
我需要澄清一下。这是我的代码。
x = [1, 2, 3]
y = [1, 2, 3]
print(x is y) # It prints false!
您误解了 is
运算符的测试内容。它测试两个变量是否指向相同的对象,而不是两个变量是否具有相同的值。
从 is
operator 的文档中:
运算符 is 和 is not 测试对象身份:当且仅当 x 和 y 是同一个对象时,x is y 为真。
请改用 ==
运算符:
print(x == y)
这将打印 True
。 x
和 y
是两个 独立 列表:
x[0] = 4
print(y) # prints [1, 2, 3]
print(x == y) # prints False
如果您使用 id()
function,您会看到 x
和 y
具有不同的标识符:
>>> id(x)
4401064560
>>> id(y)
4401098192
但如果您要将 y
分配给 x
则两者都指向同一个对象:
>>> x = y
>>> id(x)
4401064560
>>> id(y)
4401064560
>>> x is y
True
和 is
表明两者是同一个对象,它返回 True
。
请记住,在 Python 中,names are just labels referencing values;您可以有多个名称指向同一个对象。 is
告诉您两个名称是否指向同一个对象。 ==
告诉您两个名称是否指代具有相同值的对象。
Another duplicate 询问为什么两个相等的字符串通常不相同,这里没有真正回答:
>>> x = 'a'
>>> x += 'bc'
>>> y = 'abc'
>>> x == y
True
>>> x is y
False
那么,为什么它们不是同一个字符串?特别是考虑到这一点:
>>> z = 'abc'
>>> w = 'abc'
>>> z is w
True
让我们稍微推迟第二部分。第一个怎么可能是真的?
解释器必须有一个“实习表”,一个将字符串值映射到字符串对象的表,因此每次您尝试使用内容 'abc'
创建一个新字符串时,都会返回相同的对象。 Wikipedia 对实习的工作方式进行了更详细的讨论。
而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
好的,但为什么 z
和 w
相同?
那不是解释器自动实习,而是编译器折叠值。
如果相同的编译时字符串在同一个模块中出现两次(这究竟意味着什么很难定义——它与字符串文字不同,因为 r'abc'
、'abc'
和 'a' 'b' 'c'
都是不同的文字但相同的字符串——但很容易直观地理解),编译器只会创建一个字符串的实例,有两个引用。
事实上,编译器可以走得更远:优化器可以将 'ab' + 'c'
转换为 'abc'
,在这种情况下,它可以与同一模块中的 'abc'
常量折叠在一起。
同样,这是 Python 允许但不是必须做的事情。但在这种情况下,CPython 总是折叠小字符串(以及,例如,小元组)。 (尽管交互式解释器的逐语句编译器运行的优化与一次模块编译器不同,因此您不会以交互方式看到完全相同的结果。)
那么,作为程序员,你应该怎么做呢?
嗯…… 没什么。您几乎没有任何理由关心两个不可变值是否相同。如果您想知道何时可以使用 a is b
而不是 a == b
,那么您问错了问题。除了以下两种情况外,请始终使用 a == b
:
对于像 x is None 这样的单例值的更易读的比较。
对于可变值,当您需要知道改变 x 是否会影响 y 时。
w
和 z
由于编译器折叠值而相同,为什么这在 REPL 中也有效,即使使用 id()
来检查引用?在 Python 3.7 上使用 REPL
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]
在 duplicate question 的提示下,这个类比可能有效:
# - 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
is
和 is 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
和 b
的标识(也可以是 Cpython 中的内存地址)不同(即使它们的值相同)。这就是为什么当您说 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
>>>
在上面的示例中,即使 a
和 b
是两个不同的变量,a is b
也会返回 True
。这是因为 a
的类型是 int
,它是一个不可变对象。所以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
>>>
希望有帮助。
-5
或大于 256
的所有内容都将为 False。 Python 缓存 [-5, 256] 范围内的数字。
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
你可以在这里检查一个小整数。 257 以上的数字不是小的整数,所以它被计算为不同的对象。
在这种情况下,最好使用 ==
。
更多信息在这里:http://docs.python.org/2/c-api/int.html
X 指向一个数组,Y 指向另一个数组。这些数组是相同的,但 is
运算符将查看那些不相同的指针。
is
运算符的功能显示了这一点。
id
,除非您要求它。
它比较对象身份,即变量是否引用内存中的同一对象。这就像 Java 或 C 中的 ==
(比较指针时)。
一个简单的水果例子
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 ) )
is
运算符只不过是 ==
的英文版本。因为这两个列表的 ID 不同,所以答案是错误的。你可以试试:
a=[1,2,3]
b=a
print(b is a )#True
*因为两个列表的 ID 相同
is
不是“==
的英文版”
A is B
与id(A) == id(B)
相同。id(A)
存储在变量中,然后期望variable == id(B)
仍然有效;如果A
在此期间被删除,那么B
可能会被赋予相同的内存位置。variable
正在存储以前存在的某物的属性。运行时无法检测到后面的使用是错误的。标准的关键部分是“[id() ]保证对于此对象在其生命周期内是唯一且恒定的。具有非重叠生命周期的两个对象可能具有相同的 id() 值。 "