Когда использовать словарь против кортежа в Python

31

Конкретный пример - список имен файлов и их размеры. Я не могу решить, должен ли каждый элемент в списке иметь форму {"filename": "blabla", "size": 123}или просто ("blabla", 123). Словарь кажется мне более логичным, потому что, например, доступ к размеру file["size"]более понятен, чем file[1]... но я точно не знаю точно. Мысли?

CLB
источник
В качестве дополнения рассмотрите возможность распаковки кортежей , если вы беспокоитесь о читабельности кортежей fname, file_size = file, где данные - это ваш вышеприведенный кортеж, с которым можно покончить file[1]и заменить его file_size. Конечно, это зависит от хорошей документации.
nlsdfnbch
2
Это зависит от того, какую структуру данных вы строите, и как вы намереваетесь получить к ней доступ? (по имени файла? по индексу? оба?) Это просто одноразовая переменная / структура данных, или вы, возможно, будете добавлять другие элементы (/ атрибуты), а также размер? Структура должна помнить заказ; Вы хотите отсортировать список размеров или получить к нему доступ по позиции (например, «top-n самые большие / самые маленькие файлы»)? В зависимости от них «лучшим» ответом может быть dict, OrderedDict, namedtuple, простой старый список или собственный класс. Нужно больше контекста от вас.
smci

Ответы:

78

Я бы использовал namedtuple:

from collections import namedtuple
Filesize = namedtuple('Filesize', 'filename size')
file = Filesize(filename="blabla", size=123)

Теперь вы можете использовать file.sizeи file.filenameв своей программе, которая является ИМХО наиболее читаемой формой. Note namedtupleсоздает неизменяемые объекты, такие как кортежи, и они более легкие, чем словари, как описано здесь .

Док Браун
источник
1
Спасибо, хорошая идея, никогда не слышал о них до сегодняшнего дня (я довольно новичок в Python). Вопрос: что произойдет, если кто-то еще в коде также определит тот же «класс», возможно, немного по-другому. например, в каком-то другом исходном файле у коллеги БобаFilesize = namedtuple('Filesize', 'filepath kilobytes')
user949300
Вы также можете использовать очень хороший attrsмодуль (может найти его через pipили просто найти его), который позволяет вам иметь очень похожие синтаксические удобства с именованным кортежем, но может дать вам изменчивость (но также может быть сделана неизменной). Основное функциональное отличие состоит в том, что attrsклассы -made не сравниваются равными обычным кортежам, как namedtupleэто делают s.
mtraceur
3
У @DocBrown Python нет концепции объявлений. class, defИ =все просто переписывает все предыдущие использования. repl.it
Challenger5
@ Challenger5: вы правы, моя ошибка, поэтому правильный ответ таков: последнее определение имеет значение, ошибок в среде выполнения Python нет, но поведение все равно схоже с любой другой переменной.
Док Браун
8
Обратите внимание, что namedtupleэто по сути краткая декларация для нового типа с неизменяемыми атрибутами. Это означает, что ответ на самом деле «Ни, tupleни а dict, а ан object». +1
jpmc26
18

{"filename": "blabla", "size": 123} или просто ("blabla", 123)

Это старый вопрос о том, нужно ли кодировать ваш формат / схему как внутри, так и вне полосы.

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

Что касается неизменного вопроса, помните, что неизменный не означает бесполезный перед лицом изменений. Это значит, что нам нужно больше памяти, внести изменения в копию и использовать новую копию. Это не бесплатно, но часто не является нарушителем. Мы используем неизменные строки для постоянного изменения вещей.

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

Однако я не могу собрать два независимо определенных формата, которые имеют некоторые перекрывающиеся поля, а некоторые нет, хранить их в одном формате и использовать его для вещей, которые знают только об одном или других форматах.

Для этого мне нужно кодировать информацию о формате с самого начала. Мне нужно сказать "это поле является именем файла". Это позволяет множественное наследование.

Вы, вероятно, привыкли наследовать, только выражаясь в контексте объектов, но те же идеи работают для форматов данных, потому что объекты хранятся в форматах данных. Это точно такая же проблема.

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

candied_orange
источник
3
Честно говоря, я сомневаюсь, что у любого, кто не уверен в том, использовать ли внутриполосный или внеполосный формат, такие жесткие требования к производительности, что им нужно будет использовать внеполосный формат
Александр - восстановите Монику
2
@ Александр очень верно. Я предпочитаю учить людей этому, чтобы они понимали, на что они смотрят, когда сталкиваются с внешними решениями. Бинарные форматы часто делают это по причинам запутывания. Не каждый хочет быть портативным. Что касается соображений производительности, если это действительно имеет значение, рассмотрите сжатие, прежде чем прибегать к внеполосным.
candied_orange
Помните, что OP использует Python, поэтому они, вероятно, не слишком обеспокоены производительностью. Большая часть кода высокого уровня должна быть написана в первую очередь для удобства чтения; преждевременная оптимизация - корень всего зла.
Dagrooms
@Dagrooms не ненавидят Python. Это хорошо работает во многих случаях. Но в остальном я согласен со всем, что ты сказал. Я хотел сказать: «Вот почему люди так делают. Вот почему вам, вероятно, все равно».
candied_orange
@CandiedOrange Я не ненавижу язык, я использую его в своей повседневной работе. Мне не нравится, как люди используют это.
Dagrooms
7

Я бы использовал класс с двумя свойствами. file.sizeэто лучше , чем любой file[1]или file["size"].

Простое лучше, чем сложное.

JacquesB
источник
Если кому-то интересно: для генерации JSON оба работают одинаково хорошо: file = Filesize(filename='stuff.txt', size=222)и filetup = ("stuff.txt", 222)оба генерируют один и тот же JSON: json.dumps(file)и json.dumps(filetup)приводят к:'["stuff.txt", 222]'
Юха Унтинену
5

Уникальны ли имена файлов? Если это так, вы можете полностью удалить список и использовать чистый словарь для всех файлов. например (гипотетический сайт)

{ 
  "/index.html" : 5467,
  "/about.html" : 3425,
  "/css/main.css" : 9876
}

так далее...

Теперь вы не получаете «имя» и «размер», вы просто используете ключ и значение, но часто это более естественно. YMMV.

Если вам действительно нужен «размер» для ясности или вам нужно более одного значения для файла, то:

{ 
   "/index.html" : { "size": 5467, "mime_type" : "foo" },
   "/about.html" : { "size": 3425, "mime_type" : "foo" }
   "/css/main.css" : { "size": 9876, "mime_type" : "bar" }
}
user949300
источник
0

В python словарь является изменяемым объектом. С другой стороны, кортеж является неизменным объектом.

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

Если у вас есть фиксированные / статические данные, я предлагаю использовать кортеж.

# dictionary define.
a = {}
a['test'] = 'first value'

# tuple define.
b = ()
b = b+(1,)

# here, we can change dictionary value for key 'test'
a['test'] = 'second'

Но не может изменить данные кортежа с помощью оператора присваивания.

Углубить Патель
источник