2015-10-27 6 views
11

я полностью застрял с этимСтрока идентичности характер парадокс

>>> s = chr(8263) 
>>> x = s[0] 
>>> x is s[0] 
False 

Как это возможно? Означает ли это, что доступ к строковому символу путем индексирования создает новый экземпляр того же символа? Давайте эксперимент:

>>> L = [s[0] for _ in range(1000)] 
>>> len(set(L)) 
1 
>>> ids = map(id, L) 
>>> len(set(ids)) 
1000 
>>> 

Yikes что трата байт;) Или это означает, что str.__getitem__ имеет скрытую функцию? Может кто-нибудь объяснить?

Но это не конец моего удивления:

>>> s = chr(8263) 
>>> t = s 
>>> print(t is s, id(t) == id(s)) 
True True 

Это ясно: t является псевдонимом для s, поэтому они представляют собой один и тот же объект и тождества совпадают. Но опять же, как возможно следующее:

>>> print(t[0] is s[0]) 
False 

s и t являются тем же объектом, так что?

Но хуже:

>>> print(id(t[0]) == id(s[0])) 
True 

t[0] и s[0] не было мусора, рассматриваются в качестве того же объекта с помощью оператора is, но имеют разные идентификаторы? Может кто-нибудь объяснить?

+1

Ваш символ на самом деле является строка с одним элементом, так что да, доступ полукокса по индексу создает новую строку длины 1. –

+0

я получаю this- 'ValueError: Chr() ARG не в диапазоне (256) 'при Я запускаю this-'s = chr (8263)' – CrakC

+1

, как дубликат объясняет 't [0] равен s [0] -> False', даже если' id (t [0]) == id (s [0]) -> Правда'? –

ответ

7

Здесь есть два момента.

Во-первых, Python действительно создает новый символ с __getitem__ вызова, но только если этот символ имеет порядковое значение больше чем 256.

Например:

>>> s = chr(256) 
>>> s[0] is s 
True 

>>> t = chr(257) 
>>> t[0] is t 
False 

Это потому что внутренне, скомпилированная функция getitem проверяет порядковое значение одиночного chracter и вызывает get_latin1_char, если это значение равно 256 или меньше. Это позволяет использовать односимвольные строки. В противном случае создается новый объект unicode.

Вторая проблема касается сбора мусора и показывает, что интерпретатор может очень быстро использовать адреса памяти. Когда вы пишете:

>>> s = t # = chr(257) 
>>> t[0] is s[0] 
False 

Python сначала создает две новые одиночные символьные строки, а затем сравнивает их адреса памяти. Они имеют разные адреса (у нас есть разные объекты в соответствии с приведенным выше объяснением), поэтому сравнение объектов с is возвращает False.

С другой стороны, мы можем иметь, казалось бы, парадоксальная ситуация, что:

>>> id(t[0]) == id(s[0]) 
True 

Но это потому, что переводчик быстро повторно адрес памяти t[0], когда он создает новую строку s[0] на более поздний момент время.

Если вы исследуете байткод производит эту линию (например, с dis - смотри ниже), вы видите, что адреса для каждой стороны распределяются одна за другой (новый строковый объект создается, а затем id называется на нем) ,

Обращения к объекту t[0] сбрасываются до нуля, как только возвращается id(t[0]) (мы проводим сравнение по целым числам, а не по самому объекту). Это означает, что s[0] может повторно использовать тот же адрес памяти, когда он будет создан после этого.


Вот разобранном байткод для линии id(t[0]) == id(s[0]) который я аннотированный.

Вы можете видеть, что срок службы t[0] заканчивается до создания s[0] (на нем нет ссылок), поэтому его память может быть использована повторно.

2   0 LOAD_GLOBAL    0 (id) 
       3 LOAD_GLOBAL    1 (t) 
       6 LOAD_CONST    1 (0) 
       9 BINARY_SUBSCR      # t[0] is created 
      10 CALL_FUNCTION   1  # id(t[0]) is computed... 
                # ...lifetime of string t[0] over 
      13 LOAD_GLOBAL    0 (id) 
      16 LOAD_GLOBAL    2 (s) 
      19 LOAD_CONST    1 (0) 
      22 BINARY_SUBSCR      # s[0] is created... 
                # ...free to reuse t[0] memory 
      23 CALL_FUNCTION   1  # id(s[0]) is computed 
      26 COMPARE_OP    2 (==) # the two ids are compared 
      29 RETURN_VALUE 
+0

Благодарим вас за информативность и отзыв. Но возникает один вопрос: разве это не противоречит неизменности струн? По определению, неизменяемость строки 's' означает, что объект' s [valid_index] 'никогда не изменяется во время жизни строки? –

+0

@ P.Ortiz: не проблема, рад, что это помогло. Если я правильно вас понял, это не противоречит неизменности струнных объектов, насколько я могу судить. Для первой части кажется, что 's [i]' просто проверяет, находится ли i-й символ 's' в диапазоне 0-256, и, если он есть, возвращает одиночный строковый объект, заданный' chr (i) '. Для сравнения части 'id' время жизни' t [0] 'превышает Python, и поэтому' s [0] 'свободно занимает память, в которой он находился. Никакие строковые объекты не мутируются. –

+0

Я стараюсь быть более ясным: Python Ref. docs объясняет: «Когда мы говорим о изменчивости контейнера, подразумеваются только * тождества * непосредственно содержащихся объектов». Итак, предположим, что у вас есть следующая строка: 's = chr (8263)'. Если вы выполняете индексирование на 's', например, невинное присвоение как' x = s [0] ', * identity * из первого элемента в' s' имеет * changed * ('str.getitem' возвращает новое значение как объяснено в вашем ответе). Я имею в виду, что 'str .__ getitem__' является мутирующим методом (состояние строки было изменено). Но у неизменяемого объекта нет каких-либо мутирующих методов. –

0

is сравнить идентичности и == сравнить значения. Проверьте это doc

Every object has an identity, a type and a value. An object’s identity never changes once it has been created; you may think of it as the object’s address in memory. The ‘is‘ operator compares the identity of two objects; the id() function returns an integer representing its identity (currently implemented as its address). An object’s type is also unchangeable.

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

  • Нет связанных вопросов^_^