2009-09-08 2 views
53

Почему "hello" is "hello" == True в Python?Python: Почему («привет» это «привет») оценивается как True?

Я прочитал следующее here:

Если две строковые литералы равны, они были введены в то же место памяти. Строка является неизменной сущностью. Никакого вреда не может быть .

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

+0

См. Здесь вместо: http: //pyref.infogami.com/intern – bzlm

+0

Также обратите внимание на функцию 'id' для проверки мест памяти:' print id («hello») ' – Blixt

+0

bzlm, ссылка pyref.infogami.com/intern пошла мертвой, но у архиватора есть копия здесь:
http://web.archive.org/web/20090429040354/http://pyref.infogami.com/intern
Однако, хотя это часто верно, это НЕ ВСЕГДА верно, поскольку @bobince продемонстрировал очень ниже. –

ответ

80

Python (как Java, C, C++, .NET) использует пул пула/интернирование. Интерпретатор понимает, что «привет» совпадает с «привет», поэтому он оптимизирует и использует одно и то же местоположение в памяти.

Другой Гуди: «ад» + «о» является «привет» ==> True

+23

Даже C/C++ обычно это делают; «foo» == «foo» часто верен в C. В C и Python это деталь реализации; Я не думаю, что что-либо в Python * требует *, что интерпретатор делает это, а в C/C++ это оптимизация, которую делают не все компиляторы, и это может быть отключено. (Напротив, это свойство всегда * верно в Lua, все строки интернированы.) –

+2

@Glenn, вы правы, и я рад, что кто-то упомянул. Конечно, никто не должен НАСТОЯЩИМ относиться к тому, что это правда. – Triptych

+0

Это интерпретатор или компилятор для таких языков, как задание на работу c/C++, чтобы сделать эту оптимизацию, сделав то же самое, что и время компиляции. – andy

1

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

+1

Как интерпретация строк связана с неизменяемостью? Многие вещи как на Python, так и на «.NET» неизменяемы без интернирования. – bzlm

+1

Потому что, если бы возможно, чтобы строковый литерал изменялся в памяти, он не мог быть общим (или «интернирован»). – harto

+0

Правда, но с учетом того факта, что объект является неизменным, можно безопасно делиться ссылкой на экземпляр. –

2

Питон интерпретатор/компилятор обрабатывает строковые литералы, то есть цитируемый список символов. Когда он это сделает, он может обнаружить «я видел эту строку раньше» и использовать то же представление, что и в прошлый раз. Он может это сделать, поскольку он знает, что строки, определенные таким образом, не могут быть изменены.

14

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

Memory  Code 
------- 
|   myLine = "hello" 
|  /
|hello < 
|  \ 
|   myLine = "hello" 
------- 
+2

Это как раз то, что принято в ответе ... – Martin

+2

Напротив против злых нисходящих горизонтов – Martin

+4

+1: принятый ответ не имеет хорошего искусства ASCII :-) – kriss

6

Оператор is возвращает true, если оба аргумента являются одним и тем же объектом. Ваш результат является следствием этого и цитированного бита.

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

+0

Они «становятся тем же объектом»? Если вы измените одно, другое не будет изменено. – endolith

+3

@endolith: Объект, о котором идет речь, является интернированной строкой, а не переменной, назначенной этой строке. В python нет способа изменить строку. – SingleNegationElimination

57

Значит, есть одно и только одно место в памяти для каждой строки Python?

Нет, только те интерпретаторы, которые решили оптимизировать, что является решением, основанным на политике, которая не является частью спецификации языка и которая может изменяться в разных версиях CPython.

например. на моей установке (2.6.2 Linux):

>>> 'X'*10 is 'X'*10 
True 
>>> 'X'*30 is 'X'*30 
False 

аналогично для Интс:

>>> 2**8 is 2**8 
True 
>>> 2**9 is 2**9 
False 

Так что не полагаться на «строку» есть «строка»: даже просто глядя на реализацию Си, не является безопасным.

+11

Таким образом, вы всегда должны использовать '==' для сравнений равенства строк. – SingleNegationElimination

+0

Интерпретатор кэширует небольшие числа (до 256) в Python. Итак, 'a = 50; b = 50; a is b' - True, a = 500; b = 500; a is b' является ложным. –

0

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

+0

Неправда! Он рассматривает только строки и малые целые числа. Например, когда вы делаете копию списка или словаря, хотя они имеют одинаковое значение (== равенство), они не являются одним и тем же объектом («равно»). Вот почему вы можете изменить копию списка, поскольку оригинал остается неизменным (или наоборот). Большое объяснение представлено в главе «Динамический ввод» Learning Python от O'reilly – fanny

Смежные вопросы