Что это за изменения распаковка поведение вместо python2 на Питон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
Я знаю, что это, вероятно, не влияет на правильность программы, но это ошибка меня немного. Может кто-нибудь дать некоторое представление об этой разнице в распаковке?
2 ответов
это поведение, по крайней мере, частично связано с тем, как интерпретатор делает постоянное сворачивание и как 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
. The 1
является индексом в co_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
для версий, которые не складываются должным образом;filmor ссылки на 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
.
Я думаю, что это на самом деле случайно, так как я не могу воспроизвести поведение в Python 3.2.
существует эта проблема http://bugs.python.org/issue11244 это вводит CONST_STACK
чтобы исправить проблемы с постоянными кортежами с отрицательными числами, которые не оптимизируются (посмотрите на патчи против peephole.c
, который содержит оптимизатор Python).
это, по-видимому, также привело к данному поведению. Все еще глядя в это:)