С точки зрения спецификации языка, любой совместимый компилятор Python и среда выполнения полностью разрешены для любого экземпляра неизменяемого типа создать новый экземпляр ИЛИ найти существующий экземпляр того же типа, который равен требуемому значению, и использовать новая ссылка на тот же экземпляр. Это означает, что всегда некорректно использовать is
или сравнение по идентификатору неизменяемых, и любой незначительный выпуск может изменить или изменить стратегию в этом вопросе для улучшения оптимизации.
С точки зрения реализации, компромисс довольно очевиден: попытка повторно использовать существующий экземпляр может означать затраченное время (возможно, потраченное впустую), пытаясь найти такой экземпляр, но если попытка увенчается успехом, некоторая память сохраняется (а также время для выделения и последующего освобождения битов памяти, необходимых для хранения нового экземпляра).
Как решить эти компромиссы реализации, не совсем очевидно - если вы можете идентифицировать эвристики, которые указывают на то, что поиск подходящего существующего экземпляра вероятен и поиск (даже если он потерпит неудачу) будет быстрым, тогда вы можете попытаться ищите и используйте повторно, когда эвристика предложит это, но пропустите это иначе.
В ваших наблюдениях вы, кажется, нашли конкретную реализацию с выпуском точек, которая выполняет некоторую оптимизацию глазка, когда это совершенно безопасно, быстро и просто, поэтому все назначения от A до D сводятся к тому же, что и A ( но от E до F нет, так как они включают в себя именованные функции или методы, которые авторы оптимизатора могли обоснованно считать не на 100% безопасными для принятия семантики - и с низким ROI, если это было сделано - так что они не выглядят как глазок. оптимизировано).
Таким образом, повторное использование одного и того же экземпляра от A до D сводится к тому, что A и B делают это (так как C и D оптимизируются для глазка точно в одну и ту же конструкцию).
Это повторное использование, в свою очередь, четко указывает на тактику компилятора / эвристику оптимизатора, в соответствии с которой идентичные литеральные константы неизменяемого типа в локальном пространстве имен той же функции свернуты для ссылки только на один экземпляр в .func_code.co_consts
функции (для использования терминологии текущего CPython). для атрибутов функций и объектов кода) - разумная тактика и эвристика, так как повторное использование одного и того же неизменяемого константы в одной функции встречается довольно часто, и цена выплачивается только один раз (во время компиляции), тогда как преимущество накапливается много раз ( каждый раз, когда функция выполняется, может быть внутри циклов и т. д.).
(Так сложилось, что эти конкретные тактики и эвристики, учитывая их явно положительные компромиссы, были распространены во всех последних версиях CPython, а также, я полагаю, IronPython, Jython и PyPy; -).
Это несколько достойно и интересно изучить, если вы планируете писать компиляторы, среды выполнения, оптимизаторы глазков и т. Д. Для самого Python или аналогичных языков. Я предполагаю, что глубокое изучение внутренних компонентов (в идеале, конечно, множества различных правильных реализаций, чтобы не зацикливаться на причудах конкретного) - хорошая вещь, в настоящее время Python имеет как минимум 4 отдельные реализации, достойные производства, не говоря уже о несколько версий каждой!) могут также косвенно помочь сделать одного из лучших программистов на Python, но особенно важно сосредоточиться на том, что гарантирует самим языком, что несколько меньше, чем вы найдете общие для отдельных реализаций, потому что части, которые «просто случайно» являются общими в данный момент (без необходимости требуется в соответствии со спецификациями языка), вполне могут измениться под вами на следующей стадии выпуска та или иная реализация, и, если ваш производственный код ошибочно полагался на такие детали, это может вызвать неприятные сюрпризы ;-). Плюс - вряд ли когда-либо необходимо или даже особенно полезно полагаться на такие переменные детали реализации, а не на поведение, предписанное языком (если, конечно, вы не кодируете что-то вроде оптимизатора, отладчика, профилировщика или тому подобное; - ).