Лучший способ думать об этом:
- Кортеж - это запись , чьи поля не имеют имен.
- Вы используете кортеж вместо записи, если не можете указать имена полей.
Так что вместо того, чтобы писать что-то вроде:
person = {"name": "Sam", "age": 42}
name, age = person["name"], person["age"]
Или еще более многословный:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
person = Person("Sam", 42)
name, age = person.name, person.age
Вы можете просто написать:
person = ("Sam", 42)
name, age = person
Это полезно, если вы хотите передать запись, которая имеет только пару полей, или запись, которая используется только в нескольких местах. В этом случае указание совершенно нового типа записи с именами полей (в Python вы бы использовали объект или словарь, как указано выше) может быть слишком многословным.
Кортежи происходят из мира функционального программирования (Haskell, OCaml, Elm, F # и т. Д.), Где они обычно используются для этой цели. В отличие от Python, большинство функциональных языков программирования имеют статическую типизацию (переменная может содержать только один тип значения, и этот тип определяется во время компиляции). Статическая типизация делает роль кортежей более очевидной. Например, на языке вяз:
type alias Person = (String, Int)
person : Person
person = ("Sam", 42)
Это подчеркивает тот факт, что определенный тип кортежа всегда должен иметь фиксированное количество полей в фиксированном порядке, и каждое из этих полей всегда должно иметь одинаковый тип. В этом примере человек всегда является кортежем из двух полей: одно - строка, а другое - целое число.
Вышесказанное резко контрастирует со списками , которые должны иметь переменную длину (количество элементов обычно отличается в каждом списке, и вы пишете функции для добавления и удаления элементов) и каждого элемента в списке, как правило, того же типа. Например, у вас будет один список людей и другой список адресов - вы не будете смешивать людей и адреса в одном списке. Принимая во внимание, что смешивание разных типов данных внутри одного кортежа - это и есть смысл кортежей Поля в кортеже обычно бывают разных типов (но не всегда - например, у вас может быть кортеж (Float, Float, Float)
для представления координат x, y, z).
Кортежи и списки часто являются вложенными. Распространено иметь список кортежей. Вы можете иметь список кортежей Person так же, как список объектов Person. Вы также можете иметь поле кортежа, значением которого является список. Например, если у вас есть адресная книга, в которой один человек может иметь несколько адресов, у вас может быть кортеж типа (Person, [String])
. Тип [String]
обычно используется в функциональных языках программирования для обозначения списка строк. В Python вы не будете записывать тип, но вы можете использовать подобные кортежи точно таким же образом, поместив объект Person
в первое поле кортежа и список строк во второе поле.
В Python возникает путаница , потому что язык не предписывает ни одну из этих практик, которые применяются компилятором в статически типизированных функциональных языках. На этих языках нельзя смешивать разные типы кортежей. Например, вы не можете вернуть кортеж (String, String)
из функции, тип которой говорит, что она возвращает кортеж (String, Integer)
. Вы также не можете вернуть список, когда тип говорит, что вы планируете вернуть кортеж, и наоборот. Списки используются исключительно для растущих коллекций элементов, а кортежи - для записей фиксированного размера. Python не мешает вам нарушить любое из этих правил, если хотите.
В Python список иногда преобразуется в кортеж для использования в качестве ключа словаря, потому что ключи словаря Python должны быть неизменяемыми (то есть постоянными), тогда как списки Python являются изменяемыми (вы можете добавлять и удалять элементы в любое время ). Это обходной путь для конкретного ограничения в Python, а не свойство кортежей как концепция информатики.
Итак, в Python списки изменчивы, а кортежи неизменны. Но это всего лишь выбор дизайна, а не внутреннее свойство списков и кортежей в информатике. С таким же успехом вы можете иметь неизменяемые списки и изменяемые кортежи.
В Python (с использованием реализации CPython по умолчанию) кортежи также быстрее, чем объекты или словари, для большинства целей, поэтому они иногда используются по этой причине, даже если именование полей с использованием объекта или словаря будет более понятным. *
Наконец, чтобы сделать еще более очевидным, что кортежи предназначены для записи другого типа (не другого типа списка), в Python также есть именованные кортежи :
from collections import namedtuple
Person = namedtuple("Person", "name age")
person = Person("Sam", 42)
name, age = person.name, person.age
Часто это лучший выбор - короче, чем определение нового класса, но значение полей более очевидно, чем при использовании обычных кортежей, у полей которых нет имен.
Неизменяемые списки очень полезны для многих целей , но тема слишком сложна, чтобы отвечать здесь. Суть в том, что вещи, которые не могут измениться, легче рассуждать, чем вещи, которые могут измениться. Большинство программных ошибок происходят из-за непредвиденных изменений, поэтому ограничение способов их изменения - хороший способ устранения ошибок. Если вам интересно, я рекомендую прочитать учебник для функционального языка программирования, такого как Elm, Haskell или Clojure (Elm - самый дружелюбный). Разработчики этих языков считали неизменность настолько полезной, что все списки неизменны там. (Вместо того, чтобы изменять список для добавления или удаления элемента, вы создаете новый список с добавленным или удаленным элементом . Неизменность гарантирует, что старая копия списка никогда не изменится, поэтому компилятор и среда выполнения может заставить код работать хорошо, повторно используя части старого списка в новом и собирая мусор оставшиеся части, когда они более необходимы.)