При каких обстоятельствах одинаковые строки имеют одну и ту же ссылку?

Я искал веб-страницы и переполнял вопросы, но не смог найти ответ на этот вопрос. Наблюдение, которое я сделал, заключается в том, что в Python 2.7.3, если вы назначили две переменные одной и той же одиночной символьной строкой, например

>>> a = 'a' >>> b = 'a' >>> c = ' ' >>> d = ' ' 

Затем переменные будут иметь одну и ту же ссылку:

 >>> a is b True >>> c is d True 

Это справедливо и для некоторых более длинных строк:

 >>> a = 'abc' >>> b = 'abc' >>> a is b True >>> ' ' is ' ' True >>> ' ' * 1 is ' ' * 1 True 

Однако есть много случаев, когда ссылка (непредвиденно) не передается:

 >>> a = 'ac' >>> b = 'ac' >>> a is b False >>> c = ' ' >>> d = ' ' >>> c is d False >>> ' ' * 2 is ' ' * 2 False 

Может кто-нибудь объяснить причину этого?

Я подозреваю, что могут быть упрощения / замены, сделанные интерпретатором и / или некоторым механизмом кэширования, который использует тот факт, что строки python неизменяемы для оптимизации в некоторых особых случаях, но что я знаю? Я попытался сделать глубокие копии строк, используя конструктор str и функцию copy.deepcopy, но строки по-прежнему несовместимы с ссылками.

Причина, по которой у меня возникают проблемы, заключается в том, что я проверяю неравенство ссылок на строки в некоторых модульных тестах, которые я пишу для методов клонирования классов python нового стиля.

3 Solutions collect form web for “При каких обстоятельствах одинаковые строки имеют одну и ту же ссылку?”

Детали того, когда строки кэшируются и используются повторно, зависят от реализации, могут меняться от версии Python до версии Python и на нее нельзя положиться. Если вы хотите проверить строки для равенства, используйте == , а не.

В CPython (наиболее часто используемая реализация Python) строковые литералы, которые встречаются в исходном коде, всегда интернированы, поэтому, если один и тот же строковый литерал встречается дважды в исходном коде, они в конечном итоге указывают на один и тот же строковый объект. В Python 2.x вы также можете вызвать встроенную функцию intern() чтобы заставить интернатуру определенной строки, но вы на самом деле этого не должны делать.

Измените фактическую цель проверки того, неправильно ли распределены атрибуты между экземплярами: этот вид проверки полезен только для изменяемых объектов. Для атрибутов неизменяемого типа семантическая разность между общими и неразделенными объектами отсутствует. Вы можете исключить неизменяемые типы из своих тестов, используя

 Immutable = basestring, tuple, numbers.Number, frozenset # ... if not isinstance(x, Immutable): # Exclude types known to be immutable 

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

В CPython в качестве детали реализации пустая строка является общей , как и односимвольные строки, код которых находится в диапазоне Latin-1. Вы не должны зависеть от этого, так как это возможно обойти эту функцию.

Вы можете запросить строку для интернирования с использованием sys.intern ; это произойдет автоматически в некоторых случаях:

Обычно имена, используемые в программах Python, автоматически интернированы, а словари, используемые для хранения атрибутов модуля, класса или экземпляра, имеют интернированные ключи.

sys.intern выставляется так, что вы можете использовать его (после профилирования!) для производительности:

Внутренние строки полезны для получения небольшой производительности при поиске в словарях – если ключи в словаре интернированы, а ключ поиска интернирован, сопоставление ключей (после хэширования) может быть выполнено с помощью сравнения указателей вместо сравнения строк.

Обратите внимание, что intern является встроенным в Python 2.

Я думаю, что это реализация и оптимизация. Если строка короткая, они могут (и часто?) «Разделяться», но вы не можете зависеть от этого. Как только у вас будет больше строк, вы увидите, что они не совпадают.

 In [2]: s1 = 'abc' In [3]: s2 = 'abc' In [4]: s1 is s2 Out[4]: True 

более длинные строки

 In [5]: s1 = 'abc this is much longer' In [6]: s2 = 'abc this is much longer' In [7]: s1 is s2 Out[7]: False 

используйте == для сравнения строк (а не оператора is ).

Наблюдение / гипотеза OP (в комментариях ниже) о том, что это может быть связано с количеством токенов, похоже, подтверждается следующим:

 In [12]: s1 = 'abc' In [13]: s2 = 'abc' In [14]: s1 is s2 Out[14]: False 

если сравнивать с исходным примером abc выше.

 
Interesting Posts for Van-Lav

Есть ли способ, который во время запуска pygame, я также могу запустить консоль?

Регрессия с переменной Date с использованием Scikit-learn

Интерактивный ввод / вывод с использованием python

Хранение объектов пользователя в Google App Engine

Т-тест в Pandas (Python)

Использование Sphinx с расширением C с добавлением distutils

«Жесткий» контроль в сегментировании изображений с помощью python

Python Setuptools, настройка easy_install mac

Разбирайте HTML и сохраняйте исходный контент.

Бродяга не запускается. Пользователь, создавший виртуальную машину, не соответствует текущему пользователю

Добавление в 2D-списки в Python

Django не запускается с ошибкой wierd. Объект 'AttributeError:' module 'не имеет атрибута' getargspec ''

Ошибка импорта без модуля с именем zlib (пиво установленный python)

Как я могу записать данные в формате YAML в файле?

Есть ли скорость анализа или использование памяти для использования HDF5 для хранения больших массивов (вместо плоских двоичных файлов)?

Python - лучший язык программирования в мире.