"is" python 3.6 及更早版本与 3.7 中不可变对象的行为不一致
inconsistency in "is" behavior over immutable objects in python 3.6 and older vs 3.7
我在向我的学生介绍 is 运算符时发现 python(v3.6 及更早版本)和(v3 .7).
启动 python shell 和 运行:
5/2 is 2.5
或者:
(1, 2, 3) is (1, 2, 3)
在 v3.6.X 中,两者都得到 False
,但在 v3.7 中,它们变成了 True
.
我的期望是结果应该是 True,因为我认为不可变的数字对象(或它们的元组)只有一个实例。
看来至少我的想法在之前的版本中是不对的Python。
有谁知道已经进行了哪些更改来解释这种新行为?
我不确定原因和来源,但我的猜测是这与内联优化有关。
如果您为此值分配变量,身份检查将导致 False
,与之前相同。
>>> 5/2 is 2.5
True
>>> a = 5/2
>>> a is 2.5
False
关于新折叠优化的有趣说明。由于 python 是 "all runtime",无法提前优化某些内容,但它会努力尝试,尽可能多地解析范围:
>>> a = 3.14
>>> b = 3.14
>>> a is b
False
>>> a = 3.14; b = 3.14
>>> a is b
True
为什么相同的不可变对象应该占用相同的实例?
当在 python 中使用 is
时,您实质上是在询问 a
和 b
是否在内存中占用同一块内存。如果您将 a
和 b
视为不可变文字,那么 python 并没有特定的 space 来保存每种类型的不可变文字。在这种情况下它 return 为真完全有可能,如果您选择不同的文字,它完全有可能 return 为假。看看 this:
>>> a = "wtf"
>>> b = "wtf"
>>> a is b
True
>>> a = "wtf!"
>>> b = "wtf!"
>>> a is b
False
>>> a, b = "wtf!", "wtf!"
>>> a is b
True
如果您想避免这种情况,请不要对您未明确保存到内存中的内容使用 is
。
我认为这种行为是由于将 Constant 折叠从窥孔优化器(编译时操作)移动到新的 AST 优化器(运行 时间操作),[=11= 中也提到了这一点].)
回复:
My expectation was that the result should be True as I thought immutable numeric objects (or a tuple of them) have just one instance.
不变性与具有不可更改的值并不严格相同。在你称一个对象为可变或不可变之前,它是一个对象,Python 中的对象是在 运行 时间创建的。所以没有理由将可变性与对象创建和身份联系起来。但是,有一些例外,例如在以前和当前版本中都驻留了一个或一个小对象,主要是为了优化,这个规则(在 运行 时间创建对象)被操纵。阅读 了解更多详情。
My expectation was that the result should be True as I thought immutable numeric objects (or a tuple of them) have just one instance.
这种期望值得怀疑 - Python 语言无法保证这样的事情。
is
是一个非常棘手的运算符,因为您确实需要知道何时适合使用它。
例如:
>>> 5 / 2 is 2.5
>>> (1, 2, 3) is (1, 2, 3)
在一般情况下,is
的使用不当。如果您想检查 line/function 优化(实习)Python 正在做什么,它们可能是合适的,但我想这不是这里所需的用例。
is
只应在您想与常量进行比较时使用(保证只有一个实例)! guaranteed built-in constants 是:
None
NotImplemented
Ellipsis
(也称为...
)
True
False
__debug__
或您自己的类常量实例:
_sentinel = object()
def func(a=_sentinel):
return a is _sentinel
或者当您显式地将变量分配给新名称时:
a = b
a is b # <- that's expected to be True
Does anyone know what changes have been made which explains this new behaviour?
可能窥视孔优化器现在优化了更多情况(元组和数学表达式)。比如"AST-level Constant folding"(https://bugs.python.org/issue29469)在CPython 3.7中加入了(我这里故意写CPython是因为Python里面什么都没加3.7 语言规范).
我在向我的学生介绍 is 运算符时发现 python(v3.6 及更早版本)和(v3 .7).
启动 python shell 和 运行:
5/2 is 2.5
或者:
(1, 2, 3) is (1, 2, 3)
在 v3.6.X 中,两者都得到 False
,但在 v3.7 中,它们变成了 True
.
我的期望是结果应该是 True,因为我认为不可变的数字对象(或它们的元组)只有一个实例。
看来至少我的想法在之前的版本中是不对的Python。
有谁知道已经进行了哪些更改来解释这种新行为?
我不确定原因和来源,但我的猜测是这与内联优化有关。
如果您为此值分配变量,身份检查将导致 False
,与之前相同。
>>> 5/2 is 2.5
True
>>> a = 5/2
>>> a is 2.5
False
关于新折叠优化的有趣说明。由于 python 是 "all runtime",无法提前优化某些内容,但它会努力尝试,尽可能多地解析范围:
>>> a = 3.14
>>> b = 3.14
>>> a is b
False
>>> a = 3.14; b = 3.14
>>> a is b
True
为什么相同的不可变对象应该占用相同的实例?
当在 python 中使用 is
时,您实质上是在询问 a
和 b
是否在内存中占用同一块内存。如果您将 a
和 b
视为不可变文字,那么 python 并没有特定的 space 来保存每种类型的不可变文字。在这种情况下它 return 为真完全有可能,如果您选择不同的文字,它完全有可能 return 为假。看看 this:
>>> a = "wtf"
>>> b = "wtf"
>>> a is b
True
>>> a = "wtf!"
>>> b = "wtf!"
>>> a is b
False
>>> a, b = "wtf!", "wtf!"
>>> a is b
True
如果您想避免这种情况,请不要对您未明确保存到内存中的内容使用 is
。
我认为这种行为是由于将 Constant 折叠从窥孔优化器(编译时操作)移动到新的 AST 优化器(运行 时间操作),[=11= 中也提到了这一点].)
回复:
My expectation was that the result should be True as I thought immutable numeric objects (or a tuple of them) have just one instance.
不变性与具有不可更改的值并不严格相同。在你称一个对象为可变或不可变之前,它是一个对象,Python 中的对象是在 运行 时间创建的。所以没有理由将可变性与对象创建和身份联系起来。但是,有一些例外,例如在以前和当前版本中都驻留了一个或一个小对象,主要是为了优化,这个规则(在 运行 时间创建对象)被操纵。阅读
My expectation was that the result should be True as I thought immutable numeric objects (or a tuple of them) have just one instance.
这种期望值得怀疑 - Python 语言无法保证这样的事情。
is
是一个非常棘手的运算符,因为您确实需要知道何时适合使用它。
例如:
>>> 5 / 2 is 2.5
>>> (1, 2, 3) is (1, 2, 3)
在一般情况下,is
的使用不当。如果您想检查 line/function 优化(实习)Python 正在做什么,它们可能是合适的,但我想这不是这里所需的用例。
is
只应在您想与常量进行比较时使用(保证只有一个实例)! guaranteed built-in constants 是:
None
NotImplemented
Ellipsis
(也称为...
)True
False
__debug__
或您自己的类常量实例:
_sentinel = object()
def func(a=_sentinel):
return a is _sentinel
或者当您显式地将变量分配给新名称时:
a = b
a is b # <- that's expected to be True
Does anyone know what changes have been made which explains this new behaviour?
可能窥视孔优化器现在优化了更多情况(元组和数学表达式)。比如"AST-level Constant folding"(https://bugs.python.org/issue29469)在CPython 3.7中加入了(我这里故意写CPython是因为Python里面什么都没加3.7 语言规范).