Чому кортежі можуть містити елементи, що змінюються?


178

Якщо кортеж незмінний, то чому він може містити предмети, що змінюються?

Здається, суперечливість, що коли елемент, що змінюється, наприклад список, змінюється, кордон, якому він належить, вважає незмінним.

Відповіді:


205

Це відмінне запитання.

Ключове розуміння полягає в тому, що кортежі не можуть знати, чи є об'єкти, що знаходяться всередині них, змінні. Єдине, що робить об'єкт змінним - це метод, який змінює його дані. Взагалі цього способу неможливо виявити.

Ще одне розуміння полягає в тому, що контейнери Python насправді нічого не містять. Натомість вони зберігають посилання на інші об’єкти. Аналогічно, змінні Python не схожі на змінні у зібраних мовах; натомість імена змінних - це просто ключі у словнику простору імен, де вони асоціюються з відповідним об'єктом. Нед Батчердер пояснює це чудово у своїй публікації в блозі . Так чи інакше, об’єкти знають лише їх опорну кількість; вони не знають, що це за посилання (змінні, контейнери або внутрішні файли Python).

Ці два розуміння разом пояснюють вашу таємницю (чому незмінний кортеж "містить" список, здається, змінюється, коли змінюється базовий список). Насправді кортеж не змінився (він досі має ті ж посилання на інші об’єкти, що і раніше). Кортеж не міг змінитись (бо не мав мутаційних методів). Коли список змінився, кортеж не отримав повідомлення про зміну (список не знає, на нього посилається змінна, кортеж чи інший список).

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

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

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

Останній приклад показує 2-кортеж, який містить рядок і список. Сам кортеж не змінюється (тобто він не має жодних методів зміни вмісту). Аналогічно, рядок є непорушним, оскільки рядки не мають жодних способів мутування. Об'єкт списку має мутаційні методи, тому його можна змінити. Це показує, що мутаційність є властивістю типу об'єкта - деякі об'єкти мають мутаційні методи, а деякі - ні. Це не змінюється лише тому, що об’єкти вкладені.

Запам’ятайте дві речі. По-перше, незмінність не є магією - це лише відсутність мутуючих методів. По-друге, об’єкти не знають, до яких змінних чи контейнерів посилаються на них - вони знають лише кількість посилань.

Сподіваюся, це вам було корисно :-)


Чи не помиляється, що "кортежі не мають можливості знати, чи об'єкти всередині них змінні". Ми можемо виявити, якщо посилання реалізує хеш-метод, то він непорушний. Як би зробив дик чи набір. Хіба це не було б більше дизайнерським рішенням для того, якими повинні бути кортежі?
garg10may

@ garg10may 1) Виявити не можна легко без виклику, hash()тому що все, що успадковується від object (), є доступним для перегляду, тому підкласи повинні чітко вимкнути хешування. 2) Гасибільність не гарантує незмінність - легко робити приклади переміщуваних об'єктів, які можна змінювати. 3) Кортежі, як і більшість контейнерів у Python, просто мають посилання на базовий об'єкт - вони не зобов'язані перевіряти їх та робити висновки про них.
Реймонд Хеттінгер

171

Це тому, що кортежі не містять списків, рядків чи цифр. Вони містять посилання на інші об’єкти . 1 Неможливість змінити послідовність посилань, які містить кортеж, не означає, що ви не можете мутувати об'єкти, пов'язані з цими посиланнями. 2

1. Об'єкти, значення та типи (див. Другий до останнього абзацу)
2. Стандартна ієрархія типів (див .: "Незмінні послідовності")


8
У цьому питання неоднозначність. Ця відповідь повністю пояснює , чому це можливо для кортежів містять змінні об'єкти. Це не пояснює, чому кортежі були розроблені, щоб містити змінні предмети. Я думаю, що останнє є найбільш актуальним питанням.
відправник

16

Перш за все, слово "непорушний" може означати для різних людей багато різних речей. Мені особливо подобається, як Ерік Ліпперт класифікував незмінність у своєму дописі в блозі . Там він перераховує такі види непорушності:

  • Незмінність реаліо-труліо
  • Незмінність одного разу
  • Незмінність ескімоса
  • Дрібні проти глибокої незмінність
  • Незмінні фасади
  • Спостережна незмінність

Вони можуть поєднуватися різними способами, щоб зробити ще більше видів незмінності, і я впевнений, що існує більше. Вид непорушності вам здається цікавим глибокою (також відомою як транзитивна) незмінність, в якій незмінні об'єкти можуть містити лише інші незмінні об'єкти.

Ключовим моментом цього є те, що глибока незмінність - лише один із багатьох, безлічі видів незмінності. Ви можете прийняти будь-який вид, який ви хочете, до тих пір, поки ви усвідомлюєте, що ваше поняття "непорушне", ймовірно, відрізняється від чужого поняття "незмінне".


Яку незмінність мають кортежі Python?
qazwsx

3
Кортежі Python мають неглибоку (також неперехідну) незмінність.
Кен Уейн ВандерЛінде

16

Як я розумію, це питання потрібно переосмислити як питання щодо дизайнерських рішень: Чому дизайнери Python вирішили створити незмінний тип послідовності, який може містити об'єкти, що змінюються?

Для того, щоб відповісти на це питання, ми повинні думати про цілі кортежі служити: вони служать в якості швидкого , загального призначення послідовності. Зважаючи на це, стає цілком очевидно, чому кортежі незмінні, але можуть містити змінні предмети. А саме:

  1. Кортежі швидкі та ефективні в пам'яті: кортежі створюються швидше, ніж списки, тому що вони незмінні. Незмінність означає, що кортежі можна створювати як константи і завантажувати як такі, використовуючи постійне складання . Це також означає, що вони швидші та ефективніші в пам’яті, оскільки вони не потребують перерозподілу тощо. Вони трохи повільніше, ніж списки для випадкового доступу до елементів, але швидше знову для розпакування (принаймні на моїй машині). Якби кортежі були змінними, вони не були б такими швидкими для таких цілей.

  2. Кортежі загального призначення : кортежі повинні вміщувати будь-який предмет. Вони звикли (швидко) робити такі речі, як списки аргументів змінної довжини (через *оператора у визначеннях функцій). Якби кортежі не могли утримувати змінні предмети, вони були б марними для таких речей. Python повинен був би використовувати списки, які, ймовірно, сповільнюватимуть ситуацію, і, безумовно, будуть менш ефективними в пам'яті.

Отже, ви бачите, щоб виконати своє призначення, кортежі повинні бути незмінними, але також повинні вміщати змінні предмети. Якби дизайнери Python хотіли створити незмінний об'єкт, який гарантує, що всі об'єкти, які він містить, також є незмінними, вони повинні були б створити тип третьої послідовності. Виграш не вартий зайвої складності.


12

Ви не можете змінити idйого елементи. Тому він завжди буде містити однакові елементи.

$ python
>>> t = (1, [2, 3])
>>> id(t[1])
12371368
>>> t[1].append(4)
>>> id(t[1])
12371368

Це найбільш відповідна демонстрація прикладів вище. Кортеж має посилання на ті об'єкти, які не змінюються, хоча наявність максимум одного змінного компонента робить весь кортеж нечутливим.
п’єпі

5

Я вийду на кінцівку і скажу, що відповідна частина тут полягає в тому, що, хоча ви можете змінювати вміст списку або стан об'єкта, що міститься в кордоні, те, що ви не можете змінити, це те, що об'єкт або список є. Якщо у вас було щось, що залежало від того, щоб річ [3] була списком, навіть якщо вона порожня, то я міг би бачити, що це є корисним.


3

Однією з причин є те, що в Python немає загального способу перетворення мутаційного типу в незмінного (див. Відхилений PEP 351 та пов'язане обговорення, чому він був відхилений). Таким чином, неможливо було б розміщувати різні типи об'єктів у кортежах, якби це обмеження було, у тому числі майже про будь-який створений користувачем об'єкт, що не має змін.

Єдина причина, що словники та набори мають це обмеження, полягає в тому, що вони вимагають об'єктів бути хешированными, оскільки вони внутрішньо реалізовані як хеш-таблиці. Але зверніть увагу , що, по іронії долі, словники і самі набори НЕ незмінні (або hashable). Кортежі не використовують хеш об'єкта, тому його змінність не має значення.


2

Кортеж незмінний в тому сенсі, що сам кортеж не може розширюватися або стискатися, не те, що всі предмети, що містяться самі, є непорушними. Інакше кортежі тьмяні.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.