簡體   English   中英

從Python2到Python3的解包行為的這種變化是什么?

[英]What is with this change of unpacking behavior from Python2 to Python3

昨天我在Python 2和Python 3之間遇到了這個奇怪的解包差異,並且在快速谷歌搜索之后似乎沒有找到任何解釋。

Python 2.7.8

a = 257
b = 257
a is b # False

a, b = 257, 257
a is b # False

Python 3.4.2

a = 257
b = 257
a is b # False

a, b = 257, 257
a is b # True

我知道它可能不會影響程序的正確性,但它確實讓我有點煩惱。 任何人都可以在拆包時給出一些關於這種差異的見解嗎?

這種行為至少部分與解釋器如何進行常量折疊以及REPL如何執行代碼有關。

首先,請記住CPython首先編譯代碼(到AST然后是字節碼)。 然后它評估字節碼。 在編譯期間,腳本會查找不可變的對象並對其進行緩存。 它還對它們進行重復數據刪除。 如果它看到了

a = 257
b = 257

它會將a和b存儲在同一個對象上:

import dis

def f():
    a = 257
    b = 257

dis.dis(f)
#>>>   4           0 LOAD_CONST               1 (257)
#>>>               3 STORE_FAST               0 (a)
#>>>
#>>>   5           6 LOAD_CONST               1 (257)
#>>>               9 STORE_FAST               1 (b)
#>>>              12 LOAD_CONST               0 (None)
#>>>              15 RETURN_VALUE

注意LOAD_CONST 1 1co_consts的索引:

f.__code__.co_consts
#>>> (None, 257)

所以這些都加載相同的257 為什么不出現這種情況:

$ python2
Python 2.7.8 (default, Sep 24 2014, 18:26:21) 
>>> a = 257
>>> b = 257
>>> a is b
False

$ python3
Python 3.4.2 (default, Oct  8 2014, 13:44:52) 
>>> a = 257
>>> b = 257
>>> a is b
False

在這種情況下,每一行都是一個單獨的編譯單元,重復數據刪除不能跨越它們。 它的工作原理類似於

compile a = 257
run     a = 257
compile b = 257
run     b = 257
compile a is b
run     a is b

因此,這些代碼對象都將具有唯一的常量緩存。 這意味着如果我們刪除換行符,則is將返回True

>>> a = 257; b = 257
>>> a is b
True

事實上,這兩個Python版本都是如此。 事實上,這正是原因所在

>>> a, b = 257, 257
>>> a is b
True

也返回True ; 這不是因為解包的任何屬性; 它們只是放在同一個編譯單元中。

對於未正確折疊的版本,返回False ; 電影或鏈接到Ideone ,顯示2.7.3和3.2.3失敗。 在這些版本中,創建的元組不會與其他常量共享其項目:

import dis

def f():
    a, b = 257, 257
    print(a is b)

print(f.__code__.co_consts)
#>>> (None, 257, (257, 257))

n = f.__code__.co_consts[1]
n1 = f.__code__.co_consts[2][0]
n2 = f.__code__.co_consts[2][1]

print(id(n), id(n1), id(n2))
#>>> (148384292, 148384304, 148384496)

但是,這不是關於如何解開對象的變化; 它只是改變對象在co_consts中的存儲co_consts

我認為這實際上是偶然的,因為我不能用Python 3.2重現這種行為。

這個問題http://bugs.python.org/issue11244引入了一個CONST_STACK來修復常量元組的問題,其中負數未被優化(查看peephole.c的補丁,其中包含Python的優化運行)。

這似乎也導致了給定的行為。 還在調查這個:)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM