Python - операторское поведение со строкой - PullRequest
0 голосов
/ 26 апреля 2018

Я не могу понять следующее поведение.Я создаю 2 строки и использую оператор is для сравнения.В первом случае это работает по-другому.Во втором случае все работает как положено.По какой причине я использую запятую или пробел, она показывает False при сравнении с is, а когда запятая или пробел или другие символы не используются, она дает True

Python 3.6.5 (default, Mar 30 2018, 06:41:53) 
[GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.39.2)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> a = 'string'
>>> b = a
>>> b is a
True
>>> b = 'string'
>>> b is a
True
>>> a = '1,2,3,4'
>>> b = a
>>> b is a
True
>>> b = '1,2,3,4'
>>> b is a
False

IsЕсть надежная информация о том, почему Python интерпретирует строки по-разному?Я понимаю, что изначально a и b относятся к одному и тому же объекту.И тогда b получает новый объект, все еще b is a говорит True.Это немного сбивает с толку, чтобы понять поведение.

Когда я делаю это со строкой - это дает тот же результат.Что не так, когда я использую '1,2,3,4' - они оба строки.Чем отличается случай 1 и случай 2?т.е. оператор is, выдающий разные результаты для разного содержимого строк.

1 Ответ

0 голосов
/ 26 апреля 2018

Одна важная особенность этого поведения состоит в том, что Python кэширует некоторые, в основном, короткие строки (обычно не более 20 символов, но не для каждой их комбинации), чтобы они стали быстро доступными.Одной из важных причин этого является то, что строки широко используются в исходном коде Pyhton, и это внутренняя оптимизация для кэширования некоторых специальных типов строк.Словари являются одной из обычно используемых структур данных в исходном коде Python, которые используются для сохранения переменных, атрибутов и пространств имен в целом, а также для некоторых других целей, и все они используют строки в качестве имен объектов.Это значит, что каждый раз, когда вы пытаетесь получить доступ к атрибуту объекта или иметь доступ к переменной (локальной или глобальной), появляется словарь, который запускается изнутри.

Теперь причина, по которой вы получили такое странное поведение, заключается в том, что Python (реализация Cpython) по-разному обрабатывает строки в терминах интернирования.В исходном коде Python есть функция intern_string_constants , которая дает строкам проверяемую информацию для проверки, которую вы можете проверить для получения более подробной информации.Или посмотрите эту всеобъемлющую статью http://guilload.com/python-string-interning/.

Также стоит отметить, что Python имеет функцию intern() в модуле sys, которую можно использовать для интернирования строк вручную.

In [52]: b = sys.intern('a,,')

In [53]: c = sys.intern('a,,')

In [54]: b is c
Out[54]: True

YouВы можете использовать эту функцию, когда хотите закрепить поиск по словарю или когда вам нужно часто использовать конкретный строковый объект в вашем коде.

Другой моментчто не следует путать с интернирование строк в том, что когда вы делаете a == b, вы создаете две ссылки на один и тот же объект, что очевидно для этих ключевых слов, чтобы иметь одинаковые id.

Что касается знаков препинания, кажется, что если они являются одним символом, их интернируют, если их длина больше единицы. Если длина больше единицы, они не будут кэшироваться.Как уже упоминалось в комментариях, одна из причин этого может заключаться в том, что в ключевых словах и словарных ключах меньше знаков препинания.

In [28]: a = ','

In [29]: ',' is a
Out[29]: True

In [30]: a = 'abc,'

In [31]: 'abc,' is a
Out[31]: False

In [34]: a = ',,'

In [35]: ',,' is a
Out[35]: False

# Or

In [36]: a = '^'

In [37]: '^' is a
Out[37]: True

In [38]: a = '^%'

In [39]: '^%' is a
Out[39]: False

Но все же это всего лишь некоторые предположения, на которые нельзя полагаться в своих кодах,

...