несоответствие в поведении «есть» над неизменяемыми объектами в Python 3.6 и старше против 3.7 - PullRequest
0 голосов
/ 08 февраля 2019

Я представлял оператор is своим студентам, когда заметил, что в его поведении существует несоответствие между python (v3.6 и старше) и (v3.7).

Запустите оболочку Python и выполните:

5/2 is 2.5

Или:

(1, 2, 3) is (1, 2, 3)

в v3.6.X вы получите False для обоих, но в v3.7 они получаются вбыть True.

Я ожидал, что результат должен быть Истинным, поскольку я думал, что неизменяемые числовые объекты (или их кортеж) имеют только один экземпляр.

Кажется, что по крайней мере моймысль была неправильной в предыдущих версиях Python.

Кто-нибудь знает, какие изменения были внесены, что объясняет это новое поведение?

Ответы [ 4 ]

0 голосов
/ 08 февраля 2019

Я ожидал, что результат должен быть True, поскольку я думал, что неизменяемые числовые объекты (или их кортежи) имеют только один экземпляр.

Это ожидание сомнительно - таких нетвещь гарантируется языком Python.

is - довольно сложный оператор, потому что вам действительно нужно знать, когда его целесообразно использовать.

Например:

>>> 5 / 2 is 2.5
>>> (1, 2, 3) is (1, 2, 3)

Это нецелесообразное использование is в общем случае.Они могут быть подходящими, если вы хотите проверить, что делает оптимизация строк / функций (интернирование) Python, но я думаю, что это не тот вариант использования.

is следует использовать только, если вы хотитесравнивать с константами (которые гарантированно имеют только один экземпляр)! Гарантированные встроенные константы :

  • None
  • NotImplemented
  • Ellipsis (также известный как * 1031)*)
  • 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).

0 голосов
/ 08 февраля 2019

Почему неизменяемые объекты, которые одинаковы, занимают один и тот же экземпляр?

При использовании is в python вы по существу спрашиваете, занимают ли a и b один и тот же фрагмент в памяти.Если вы думаете о a и b как о неизменяемых литералах, это не значит, что в python есть специальное пространство для сохранения каждого типа неизменяемого литерала.Это чистый шанс, что в этом случае он вернул true, и вполне возможно, что он вернет 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 для вещей, которые вы явно не сохранили в памяти.

0 голосов
/ 08 февраля 2019

Я полагаю, что это связано с перемещением свертывания констант из оптимизатора глазка (операция времени компиляции) в новый оптимизатор AST (операция времени выполнения), который, как это также упоминается в https://docs.python.org/3/whatsnew/3.7.html#optimizations, теперь можетвыполнять оптимизацию более последовательно.(Внесено Юджином Тодером и ИНАДА Наоки в bpo-29469 и bpo-11549 .)

Re:

Мои ожидания быличто результат должен быть Истинным, так как я думал, что неизменяемые числовые объекты (или их кортеж) имеют только один экземпляр.

Неизменяемость не совсем совпадает с неизменяемым значением.Прежде чем вызывать объект, изменяемый или неизменный, это объект, и объекты в Python создаются во время выполнения.Поэтому нет причин связывать изменчивость с созданием объекта и идентичностью.Однако существуют некоторые исключения, такие как этот один или небольшой объект, преобразующийся как в предыдущую, так и в текущую версии, которые, в основном для оптимизации, этим правилом (создание объекта во время выполнения) манипулируются.Прочитайте https://stackoverflow.com/a/38189759/2867928 для более подробной информации.

0 голосов
/ 08 февраля 2019

Я не уверен в причинах и причинах этого, но я предполагаю, что это как-то связано с поточной оптимизацией.

Если вы назначите переменную для этих значений, проверка идентичностирезультат в False, как и прежде.

>>> 5/2 is 2.5
True
>>> a = 5/2
>>> a is 2.5
False

Интересное примечание по новой оптимизации свертывания.Поскольку python является «все время выполнения», нет возможности оптимизировать некоторые вещи впереди, но он старается изо всех сил, анализируя столько возможностей, сколько может:

>>> a = 3.14
>>> b = 3.14
>>> a is b
False
>>> a = 3.14; b = 3.14
>>> a is b
True
...