我被介绍是运营商给我的学生时,我注意到,在Python(3.6版以上)和(3.7版)之间的行为不一致。
启动一个Python shell并运行:
5/2 is 2.5
要么:
(1, 2, 3) is (1, 2, 3)
在v3.6.X你False
两个,但在V3.7他们练得True
。
我的期望是,结果应该是真实的,因为我以为不可改变的数字对象(或它们的元组)只有一个实例。
看来,至少我的想法是不正确的Python的早期版本。
有谁知道已经进行了什么样的变化,说明此项新的行为?
我不知道原因和来源,这一点,但我的猜测是,这已经是与在线优化。
如果你将这个值赋给变量,身份检查将导致False
,和以前一样。
>>> 5/2 is 2.5
True
>>> a = 5/2
>>> a is 2.5
False
新的折叠优化有趣的说明。由于蟒蛇是“所有运行时”,有没有办法提前优化了一些东西,但它力图,解析尽可能多的范围,因为它可以:
>>> a = 3.14
>>> b = 3.14
>>> a is b
False
>>> a = 3.14; b = 3.14
>>> a is b
True
我的期望是,结果应该是真实的,因为我以为不可改变的数字对象(或它们的元组)只有一个实例。
这种期望是值得怀疑的 - 有由Python语言保证没有这样的事情。
is
是一个相当棘手的操作,因为你真的需要知道什么时候适合使用它。
例如:
>>> 5 / 2 is 2.5
>>> (1, 2, 3) is (1, 2, 3)
这些都不是在一般情况下is
适当的用途。如果要检查什么线/功能优化(实习)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
有谁知道已经进行了什么样的变化,说明此项新的行为?
也许窥视孔优化现在更优化的情况下(元组和数学表达式)。例如,“AST-级别的常量折叠”(https://bugs.python.org/issue29469)已在CPython的3.7加(我故意写的CPython这里,因为它是已被添加到了Python 3.7语言规范没有)。
我认为,这种行为是由于移动从窥孔优化的常数合并(编译时运转)向新的AST优化器(运行时操作),这是它在https://docs.python.org/3/whatsnew/3.7.html#optimizations也提到现在能够更稳定地进行优化。 (在bpo-29469和bpo-11549供稿尤金Toder和INADA直树。)
Re:
我的期望是,结果应该是真实的,因为我以为不可改变的数字对象(或它们的元组)只有一个实例。
不变性是不严格相同,具有不可改变的值。你调用一个对象可变或不可变之前,它是在Python对象和对象是在运行时创建的。因此没有理由可变性连接对象的创建和身份。有,但是,有一些例外象在,主要用于优化的缘故,这条规则(对象创建在运行时)被操纵两个以前和当前版本实习这一个或小物件。阅读https://stackoverflow.com/a/38189759/2867928了解更多详情。
为什么要不可改变的是相同占据相同的实例对象?
当使用Python is
,你基本上是问a
和b
占用内存中的同一块。如果你觉得a
和b
作为不可改变的文字的,它不是像Python有一个特定的空间来保存所有类型的不可变的文字的。这是纯粹的机会,它在这种情况下返回真实,完全有可能的,如果你选择一个不同的文字也将返回false。看看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
。