Почему кортежи могут содержать изменяемые элементы? - PullRequest
170 голосов
/ 18 марта 2012

Если кортеж неизменен, то почему он может содержать изменяемые элементы?

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

Ответы [ 8 ]

189 голосов
/ 18 марта 2012

Это отличный вопрос.

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

Другое понимание состоит в том, что контейнеры Python на самом деле ничего не содержат. Вместо этого они хранят ссылки на другие объекты. Аналогично, переменные Python не похожи на переменные в скомпилированных языках; вместо этого имена переменных - это просто ключи в словаре пространства имен, где они связаны с соответствующим объектом. Нед Батчелдер хорошо объясняет это в своем блоге . В любом случае, объекты знают только свой счетчик ссылок; они не знают, что это за ссылки (переменные, контейнеры или внутренние компоненты Python).

Вместе эти две идеи объясняют вашу загадку (почему неизменный кортеж, «содержащий» список, кажется, меняется при изменении базового списка). Фактически, кортеж не изменился (он по-прежнему имеет те же ссылки на другие объекты, что и раньше). Кортеж не мог измениться (потому что у него не было методов мутации). Когда список изменился, кортеж не получил уведомление об изменении (список не знает, ссылается ли он на переменную, кортеж или другой список).

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

  1. Кортежи характеризуются в меньшей степени своей неизменностью, а в большей степени - по назначению.
    Кортежи - это способ Python собирать разнородную информацию под одной крышей. Например, s = ('www.python.org', 80) объединяет строку и число, так что пара хост / порт может передаваться как сокет, составной объект. С этой точки зрения вполне разумно иметь изменяемые компоненты.

  2. Неизменяемость идет рука об руку с другим свойством, hashability . Но hashability не является абсолютным свойством. Если один из компонентов кортежа не является хэшируемым, то и весь кортеж не может быть хэшируемым. Например, t = ('red', [10, 20, 30]) не является хэшируемым.

Последний пример показывает 2-кортеж, который содержит строку и список. Сам кортеж не является изменяемым (т. Е. У него нет методов для изменения его содержимого). Аналогично, строка является неизменной, потому что строки не имеют никаких методов мутации. У объекта списка есть методы мутации, поэтому его можно изменить. Это показывает, что изменчивость является свойством типа объекта - некоторые объекты имеют методы мутации, а некоторые нет. Это не изменится только потому, что объекты вложены.

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

Надеюсь, это было полезно для вас: -)

168 голосов
/ 18 марта 2012

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

1. Объекты, значения и типы (см .: от второго к последнему абзацу)
2. Стандартная иерархия типов (см .: «Неизменяемые последовательности»)

16 голосов
/ 18 марта 2012

Насколько я понимаю, этот вопрос необходимо перефразировать как вопрос о проектных решениях: почему разработчики Python решили создать тип неизменяемой последовательности, который может содержать изменяемые объекты?

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

  1. Кортежи быстрые и эффективны для памяти: кортежи создаются на быстрее, чем списки , поскольку они неизменяемы. Неизменяемость означает, что кортежи можно создавать как константы и загружать как таковые, используя постоянное свертывание . Это также означает, что они быстрее и эффективнее в создании, потому что нет необходимости в перераспределении и т. Д. Они немного на медленнее , чем списки для произвольного доступа к элементам, но снова быстрее для распаковки (по крайней мере, при моя машина). Если бы кортежи были изменяемыми, они бы не были такими быстрыми для таких целей.

  2. Кортежи общего назначения : кортежи должны содержать любой объект. Они используются (быстро) для таких вещей, как списки аргументов переменной длины (через оператор * в определениях функций). Если кортежи не могут содержать изменяемые объекты, они будут бесполезны для подобных вещей. Python должен был бы использовать списки, которые, вероятно, замедляли бы работу и, конечно, были бы менее эффективными в использовании памяти.

Итак, вы видите, что для выполнения своей цели кортежи должны быть неизменными, но также должны иметь возможность содержать изменяемые объекты. Если бы разработчики Python хотели создать неизменяемый объект, который гарантирует, что все объекты, которые он «содержит», также являются неизменяемыми, им пришлось бы создать третий тип последовательности. Усиление не стоит дополнительной сложности.

16 голосов
/ 18 марта 2012

Прежде всего, слово «неизменный» может означать много разных вещей для разных людей. Мне особенно нравится, как Эрик Липперт классифицировал неизменность в своем блоге . Там он перечисляет такие виды неизменности:

  • Realio-Trulio неизменяемость
  • неизменяемость при однократной записи
  • неизменность эскимо
  • Мелкая и глубокая неизменность
  • Неизменяемые фасады
  • Наблюдательная неизменность

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

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

11 голосов
/ 18 марта 2012

Вы не можете изменить id его предметов. Поэтому он всегда будет содержать одни и те же элементы.

$ python
>>> t = (1, [2, 3])
>>> id(t[1])
12371368
>>> t[1].append(4)
>>> id(t[1])
12371368
5 голосов
/ 18 марта 2012

Я выйду на задний план и скажу, что важная часть здесь заключается в том, что хотя вы можете изменять содержимое списка или состояние объекта, содержащегося в кортеже, вы не можете изменить это что объект или список есть. Если бы у вас было что-то, что зависело от того, что [3] было списком, даже если оно пустое, я мог бы убедиться, что это полезно.

3 голосов
/ 24 января 2013

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

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

2 голосов
/ 18 марта 2012

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

...