Оператор is ведет себя по-разному при сравнении строк с пробелами

Я начал изучать Python (Python 3.3), и я пробовалis оператор. Я попробовал это:

>>> b = 'is it the space?'
>>> a = 'is it the space?'
>>> a is b
False
>>> c = 'isitthespace'
>>> d = 'isitthespace'
>>> c is d
True
>>> e = 'isitthespace?'
>>> f = 'isitthespace?'
>>> e is f
False

Кажется, что пространство и знак вопроса делаютis вести себя по-другому. Какие'происходит?

РЕДАКТИРОВАТЬ: Я знаю, что я должен использовать==Я просто хотел знать почемуis ведет себя так

 Dmitry Zagorulkin26 мая 2013 г., 12:23
 Ben Jackson26 мая 2013 г., 08:21
Возможно, что-то вроде интернирования строк вызываетa is b (замечая строковую константу, назначеннуюb уже был создан и используется повторно). Правило интернирования должно заботиться о пробелах (или, возможно, длине)
 Nolen Royalty26 мая 2013 г., 08:34
Для любой причиныid('ab') последовательно возвращает то же значение в моей оболочке, в то время какid('a ') последовательно меняется. Я до сих пор понятия не имею, почему письма будут иметь другое поведение, но этоИнтересно наблюдать. Возможно, Python делает какую-то оптимизацию, предполагая, что строки часто содержат буквы? Я нене думаю, что это имело бы много смысла, но этоСложно объяснить это поведение. Это интересный вопрос.
 jamylak26 мая 2013 г., 10:23
Я все еще хотел бы увидеть окончательный ответ на этот вопрос относительно CPython
 jamylak26 мая 2013 г., 08:10
Для записи вы должны использовать== сравнить любой элемент на равенство, но, тем не менее, это интересный вопрос
 awesoon26 мая 2013 г., 08:22
Хм ... У меня разные результаты при использовании файла вместо записи в интерпретаторе.То же самое в идеоне.
 glglgl26 мая 2013 г., 10:40
Как вы уже знаете о чемis действительно, возможноэтот вопрос было бы полезно - если бы в нем содержался полезный ответ.

Ответы на вопрос(5)

Решение Вопроса

этот ответ о деталях реализации конкретного интерпретатора Python. сравнивая строки сis== плохая идея.

Ну, по крайней мере, для cpython3.4 / 2.7.3 ответ таков:нет, это не пробел, Нетолько пробел:

Два строковых литерала будут совместно использовать память, если они либо алфавитно-цифровые, либо находятся на одном и том жеблок (файл, функция, класс или отдельная команда интерпретатора)

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

Отдельные персонажи уникальны.

Примеры

Буквенно-цифровые строковые литералы всегда совместно используют память:

>>> x='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
>>> y='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
>>> x is y
True

Не алфавитно-цифровые строковые литералы разделяют память тогда и только тогда, когда они разделяют включающий синтаксический блок:

(Интерпретатор)

>>> x='`[email protected]#$%^&*() \][=-. >:"?<a'; y="`[email protected]#$%^&*() \][=-. >:"?<a" ;="">>> z='`[email protected]#$%^&*() \][=-. >:"?<a';>>> x is y
True 
>>> x is z
False 
</a';></a';>

(файл)

x='`[email protected]#$%^&*() \][=-. >:"?<a'; y="`[email protected]#$%^&*() \][=-. >:"?<a" ;="" z="(lambda" :="" '`[email protected]#$%^&*()="" \][="-.">:"?<a')() print(x="" is="" y)="" z)="" <="" code=""></a')()></a';>

Выход:<code>True</code> а также<code>False</code>

Для простых бинарных операций компилятор делает очень простое постоянное распространение (см.<a href="http://hg.python.org/cpython/file/0a7d237c0919/Python/peephole.c">peephole.c</a>), но со строками это происходит только в том случае, если результирующая строка короче 21 символа. В этом случае действуют упомянутые ранее правила:

<code>>>> 'a'*10+'a'*10 is 'a'*20
True
>>> 'a'*21 is 'a'*21
False
>>> 'aaaaaaaaaaaaaaaaaaaaa' is 'aaaaaaaa' + 'aaaaaaaaaaaaa'
False
>>> t=2; 'a'*t is 'aa'
False
>>> 'a'.__add__('a') is 'aa'
False
>>> x='a' ; x+='a'; x is 'aa'
False
</code>

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

<code>>>> chr(0x20) is ' '
True
</code>
 Elazar26 мая 2013 г., 22:42
@pepr вы можете заглянуть внутрь и рассказать нам. Мне было легче стучать по стенам; но во что бы то ни стало - давай. Заглянуть внутрь реализации - действительно верный способ сделать это.
 Sam Bruns20 апр. 2015 г., 21:19
@Elazar: Отличный ответ +1 :) Где вы нашли эту информацию. В каком исходном файле это реализовано?
 glglgl26 мая 2013 г., 22:23
@lftahdis.dis(lambda: 'x'*20) результаты,LOAD_CONST 3 ('xxxxxxxxxxxxxxxxxxxx')dis.dis(lambda: 'aaaaa' + "aaa") вLOAD_CONST 3 ('aaaaaaaa'), Я мог представить, что вызов метода (например,.join() является "слишком сложно" В этом смысле.
 glglgl26 мая 2013 г., 10:57
Вероятно, тогда строки не интернируются, как я думал раньше, а взяты - как строковые литералы - из того же пула строк внутри модуля.
 Elazar26 мая 2013 г., 22:31
Похоже, что компилятор делает простое постоянное распространение, включая '*' или '+' если результат меньше 21 символа.
 glglgl26 мая 2013 г., 10:57
Отличный ответ, кстати. +1.
 Ashwini Chaudhary26 мая 2013 г., 23:35
+1 отличный ответ, если кто-то используетОболочка Ipython затемx='`[email protected]#$%^&*() \][=-. >:"?:"?
 glglgl26 мая 2013 г., 22:25
КСТАТИ,dis.dis(lambda: 'x'*21) приводит кLOAD_CONST 1 ('x') LOAD_CONST 2 (21) BINARY_MULTIPLY
 Elazar26 мая 2013 г., 22:34
@pepr, мыуже прошел через это. Детали реализации - вот что интересно. Мы не пытаемся научить, как правильно использовать python прямо сейчас.
 Iftah26 мая 2013 г., 14:03
Возможно, что когда вы жестко код'a'*20  (или добавление строковых литералов) интерпретатор принимает оптимизирующее решение и заменяет его полученной строкой'aaaaaaaaaaaaaaaaaaaa', поэтому во время выполнения не выполняется никаких манипуляций со строками (более быстрое выполнение, но больший скомпилированный код); но когда умножение слишком велико, оптимизация не активируется, чтобы сохранить небольшой размер кода.
 pepr26 мая 2013 г., 22:39
@Elazar: Понятно. Тогда нетлучше заглянуть внутрь реализации?
 Elazar20 апр. 2015 г., 22:17
Благодарю. Там'Ссылка в ответе. Но в целом я просто играл с REPL.
 pepr26 мая 2013 г., 22:31
То, что вы показываете, это только то, как ведет себя эта конкретная реализация. Другими словами, это только детали реализации, оптимизация, и это не должно рассматриваться как особенность языка. Подумайте о ситуации, когда алгоритм будет распространяться. Операторis Не следует злоупотреблять только из-за особенностей реализации.

сть их физических адресов). Так что вместо твоего это сравнение:

>>> b = 'is it the space?'
>>> a = 'is it the space?'
>>> a is b
False

Ты можешь сделать:

>>> id(a) == id(b)
False

Но обратите внимание, что если бы a и b были непосредственно в сравнении, это сработало бы.

>>> id('is it the space?') == id('is it the space?')
True

На самом деле, в выражении естьразделение между одними и теми же статическими строками. Но в масштабе программыОбмениваться только для словоподобных строк (таким образом, ни пробелы, ни знаки пунктуации).

Вы не должны полагаться на это поведение какнигде не документирован и является деталью реализации. '

is Оператор - это тождественный оператор. Используется для сравненияобъект идентичность. Если вы создаете два объекта с одинаковым содержимым, то, как правило, это не тот случай, когда идентичность объекта выдает true. Это работает для некоторых небольших строк, потому что CPython, эталонная реализация Python, хранитсодержание отдельно, делая все эти объекты ссылками на одно и то же строковое содержимое. Итакis Оператор возвращает true для тех.

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

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

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

 jamylak26 мая 2013 г., 11:00
@sapi даже python3 не должен этого делать
 detly26 мая 2013 г., 12:31
@LennartRegebro - вы можете сравнить два логических выражения на равенство (в этом случае,== верно).
 pepr26 мая 2013 г., 22:12
@ChrisMorgan: Вы должны больше думать об этом.a is False является действительно плохая идея (независимо от того,False а такжеTrue переменные, константы или ключевые слова. С лингвистической / логической точки зрения подумайте о таких выражениях, какif not ambiguous is False then... (ambiguous неправильный идентификатор сам по себе).a is False это способ выражения простой истины, используя довольно сложный способ. И это не то, что нужно делать при программировании.
 sapi26 мая 2013 г., 10:28
Любой, кто читает это с помощью Python 2.x, также должен знать, что он не должен использоватьa is FalseБулевыт синглетоны.
 sapi26 мая 2013 г., 15:23
@ChrisMorgan - типFalse = True в оболочку; тот'почему по сравнению сTrue или жеFalse вообще не делаетне имеет никакого смысла.
 pepr27 мая 2013 г., 10:41
Да. +1. Во всяком случае, мы всегда должны идти к сути проблемы.
 Chris Morgan26 мая 2013 г., 15:17
@sapi: как насчет Python 2.5 или новее? Я считаю, что, принимая эту минимальную версию, они "одиночки» (не правильное слово, но этосделаю); это действительно не так? Можете привести пример?
 Chris Morgan27 мая 2013 г., 00:51
@pepr: конечно, я знаю, чтоis True а такжеis False почти никогда не будет правильным способом сделать это, но я возражаю против @sapi 'Это оригинальный способ выразить, что причина этого не должнане использовать это "булевы ареныт синглтоны ".
 Chris Morgan26 мая 2013 г., 16:02
Ах да, я так думаю, но это нет, само по себе, значитis True или жеis False плохая идея Если кто-то делает такие вещи, как присвоение именFalse или жеTrue им следуетожидать вещи сломать. Если тождество сравнение с именамиTrue а такжеFalse не звук, то присвоение значенийTrue а такжеFalse Точно так же не звук.
 Lennart Regebro26 мая 2013 г., 12:10
a is False не имеет смысла. Правильное написание есть.not a
 Elazar26 мая 2013 г., 12:12
a is False красивый английский. Видимо, это слишком хорошо, чтобы быть правдой :)

is Оператор полагается наid функция, котораяguaranteed to be unique among simultaneously existing objects. В частности,id возвращает объектадрес памяти. Похоже, что CPython имеет согласованные адреса памяти для строк, содержащих только символы a-z и A-Z.

Однако, похоже, это имеет место только в том случае, если строка была назначена переменной:

Здесь идентификаторFoo» и идентификаторa подобные.a был установлен на "Foo» до проверки идентификатора.

>>> a = "foo"
>>> id(a)
4322269384
>>> id("foo")
4322269384

Тем не менее, идентификатор "бар" и идентификаторa различаются при проверке идентификаторабар" до настройкиa равно "бар".

>>> id("bar")
4322269224
>>> a = "bar"
>>> id(a)
4322268984

Проверка идентификаторабар" сновапосле установкаa равно "бар" возвращает тот же идентификатор.

>>> id("bar")
4322268984

Таким образом, кажется, что cPython сохраняет согласованные адреса памяти для строк, содержащих только a-zA-Z, когда эти строки назначены переменной. Это'Также вполне возможно, что это зависит от версии: I 'м работает Python 2.7.3 на MacBook. Другие могут получить совершенно другие результаты.

 Nolen Royalty26 мая 2013 г., 09:08
@ Elazar спасибо, это действительно то, что я имел в виду.
 Elazar26 мая 2013 г., 09:06
Я буду удивлен, если это зависит от машины. Вы, вероятно, имеете в видузависит от версии ".

c is d также должен быть ложным. Я предполагаю, что Python делает некоторую оптимизацию, и в этом случае это тот же объект.

 creack26 мая 2013 г., 08:27
@ Elazar моя точка зрения точно. Пул - это оптимизация, и строки с пробелами просто находятся вне области видимости. @poke прав, не стоит полагать, чтоc is d
 Elazar26 мая 2013 г., 08:24
CPython хранит пул часто используемых объектов - короткие строковые литералы и примитивы типа int в диапазоне 1-100. Нет оснований предполагатьc is d должно быть ложным.
 jamylak26 мая 2013 г., 08:26
@Elazar-5 в255
 Elazar26 мая 2013 г., 08:30
@creack, очевидно, ОП спрашивает именно об этих деталях реализации. Я предполагаю, что он знает, чтобы не использовать их.
 Elazar26 мая 2013 г., 08:29
@jamylak Я имел в виду "по крайней мере"Я не знал точного диапазона ... спасибо.
 poke26 мая 2013 г., 08:26
Но с другой стороны, нужноне Предположим, чтоc is d правда.

Ваш ответ на вопрос