提问人:frost101 提问时间:2/23/2021 最后编辑:xdhmoorefrost101 更新时间:2/23/2021 访问量:94
为什么“is”运算符在算术相等的表达式中表现意外
Why does the 'is' operator behave unexpectedly with arithmetically equal expressions
问:
a = 1000
b = 1000
print (a == b)
print (a is b)
print (f"id(a) = {id(a)} \nid(b) = {id(b)}")
不出所料,我得到了
True
True
id(a) = 2806705928816
id(b) = 2806705928816
但是当我尝试做这样的事情时:
a = 1000
b = 1000 + a - a
print (a == b)
print (a is b)
print (f"id(a) = {id(a)} \nid(b) = {id(b)}")
我进入了表情False
a is b
True
False
id(a) = 3030783801968
id(b) = 3030783802064
为什么在将表达式的结果赋值给整数和将表达式的结果与其他变量赋值时,变量的行为会有所不同?尽管从数学上讲,这给出了相同的整数。
答:
区别在于对位置的引用。 '==' 检查数据类型和值是否相等,然而,'is;引用变量在内存中的位置。
对于以下情况,is 将返回 false
id(a) = 3030783801968 <----
id(b) = 3030783802064 <----
对于以下内容,is 将返回 true
id(a) = 2806705928816 <----
id(b) = 2806705928816 <----
评论
==
is
当你做这样的事情时:
(案例-1)
a = 1000
b = a
或(案例 2)
a = 1000
b = 1000
Python 足够聪明,可以事先知道即使在执行后也不需要新的内存。
因此,在第一种情况下,python 在执行之前会创建一个别名。b
a
第二种情况略有不同。
Python 是一种真正的面向对象语言,文字被视为一个对象。(直观地说,你可以把 1000 看作是 const 对象的名称)。1000
所以在第二种情况下,从技术上讲,两者都变成了a
b
alias
1000
现在在您的示例中:
a = 1000
b = 1000 + a - a
print (a == b)
print (a is b)
虽然赋值 ,但 Python 事先并不知道 的值是多少。当我说事先时,我的意思是在开始任何形式的计算之前。因此,python 为该位置保留了一个新的内存位置,然后将操作的输出保存在这个新的内存位置。b
a
b
还值得注意的是:
4-1 is 3
True
在这种情况下,python 不会保存此行,而是在编译之前对其进行处理,以进行运行时优化。4-1
3
Python 通过逐个计算其表达式来执行语句,然后对这些值执行一些操作。
来源:https://courses.cs.washington.edu/courses/cse140/13wi/eval_rules.pdf
基本上 b = 1000 + a - a 不是一次性完成的,而是在多次评估中完成的,python 将每次评估时 b 的结果存储在与 a 不同的内存位置。此时,a 和 b 是不同的对象。
使用 == 进行相等性检查。
使用“is”检查对象是否相同(变量引用相同的内存位置)。
你已经有一些准确的答案了。在这里,我给出一个“返璞归真”的答案。
什么?==
Python 的意思是左边的值与右边的值相同。==
sum([5, 7]) == (48 * 3)**0.5
是。它需要几个计算步骤才能使每个表达式达到 的值。即便如此,整数也与浮点数进行比较,因此需要将整数最终转换为浮点数。True
12
12
12.0
关键要点:对每个表达式进行评估并比较结果值。如果它们相等,则表达式为真。
什么?is
Python 另一方面,意味着左边的名称指向与右边的名称相同的对象。is
a = 3.14159
b = a
a is b
是。 已分配给值 。但更重要的是,有一个内存块保存一个对象,在本例中是浮点数 3.14159。 指向该对象/内存块。 指向 ,这意味着它指向同一内存块。True
a
3.14159
a
b
a
你可以很容易地测试这一点:创建两个只指向一个数字的“名称”,然后使用 进行比较,它们将不匹配:is
>>> a = 1239481203948
>>> b = 1239481203948
>>> a is b
False
这是错误的,因为我们现在在内存/对象中有两个不同的位置指向它们中的每一个:
>>> id(a)
140402381635344
>>> id(b)
140402391174416
(在您的计算机上,您将获得一组不同的 id
s。
因此,实际上,您“浪费”了空间,因为您有两个对象占用了相同信息的空间。
但是等等,还有更多
如果你自己玩这个,你会发现我写的东西有很多例外,并让自己感到困惑。这里只是其中的几个:
>>> a = 157
>>> b = 157
>>> a is b
True
什么??为什么会这样?为了优化 Python,“最常见的数字”已经过优化。我可能错了,但我记得内存中有最常见的数字指定空间。这些是前几百个整数,以及其他一些整数。
但还有其他优化:
>>> a = None
>>> b = None
>>> a is b
True
>>> a = True
>>> b = True
>>> a is b
True
这些仍然遵循与我之前所说的相同的规则:计算结果的原因是因为 并且都指向内存/对象中的相同位置。is
True
a
b
由于 Python 中的优化,这发生在这些奇怪的情况下。但一般而言,确保计算结果为 True
的唯一方法是将名称分配给已经具有名称的对象,就像我们写的那样:
>>> a = 3.14159
>>> b = a
>>> a is b
True
而不是写作
>>> a = 3.14159
>>> b = 3.14159
>>> a is b
False
评论
a is b
is
==
is
id()