Quando usar um dicionário vs tupla em Python

31

O exemplo específico em mente é uma lista de nomes de arquivos e seus tamanhos. Não consigo decidir se cada item da lista deve ter o formato {"filename": "blabla", "size": 123}ou apenas ("blabla", 123). Um dicionário me parece mais lógico, porque acessar o tamanho, por exemplo, file["size"]é mais explicativo do que file[1]... mas eu realmente não tenho certeza. Pensamentos?

clb
fonte
Como um adendo, considere a descompactação da tupla , se você se preocupa com a legibilidade das tuplas - fname, file_size = file, onde os dados são sua tupla acima, eliminariam file[1]e substituiriam file_size. Claro que isso depende de uma boa documentação.
Nsdfnbch
2
Depende de qual estrutura de dados você está construindo e como pretende acessá-la? (por nome do arquivo? pelo índice? ambos?) É apenas uma variável descartável / estrutura de dados ou você possivelmente adicionará outros itens (/ atributos) e tamanho? A estrutura precisa se lembrar de uma ordem; você deseja classificar a lista de tamanhos ou acessá-la por posição (por exemplo, "os maiores / menores arquivos")? Dependendo dessas, a 'melhor' resposta pode ser dict, OrderedDict, nomeado duplo, lista antiga simples ou uma classe personalizada de sua preferência. Precisa de mais contexto de você.
SMCI

Respostas:

78

Eu usaria um namedtuple:

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

Agora você pode usar file.sizee file.filenameem seu programa, que é a forma mais legível de IMHO. O Note namedtuplecria objetos imutáveis, como tuplas, e eles são mais leves que os dicionários, conforme descrito aqui .

Doc Brown
fonte
1
Obrigado, boa ideia, nunca ouvi falar deles antes de hoje (sou bastante novato em Python). Pergunta: o que acontece se alguém em outra parte do código também define a mesma "classe", possivelmente um pouco diferente. por exemplo, em algum outro arquivo de origem, o colega de trabalho que Bob tinhaFilesize = namedtuple('Filesize', 'filepath kilobytes')
user949300
Você também pode usar o attrsmódulo muito bom (você pode encontrá-lo através pipou apenas procurá-lo), que permite conveniências sintáticas muito semelhantes às tuplas nomeadas, mas pode fornecer a mutabilidade (mas também pode ser imutável). A principal diferença funcional é que as attrsclasses criadas não se comparam às tuplas simples, da mesma forma que namedtupleas fazem.
Mtraceur
3
O @DocBrown Python não tem conceito de declarações. class, defE =tudo apenas substituir quaisquer utilizações anteriores. repl.it
Challenger5
@ Challenger5: você está certo, meu erro, então a resposta correta é: a última definição conta, nenhum erro no tempo de execução do Python, mas ainda assim um comportamento semelhante ao de qualquer outra variável.
Doc Brown
8
Observe que namedtupleé essencialmente uma declaração curta para um novo tipo com atributos imutáveis. Isso significa que a resposta é efetivamente: "Nem um tuplenem um dict, mas um object". 1
jpmc26 /
18

{"filename": "blabla", "size": 123} ou apenas ("blabla", 123)

Essa é a questão antiga: codificar seu formato / esquema dentro ou fora da banda.

Você troca alguma memória para obter a legibilidade e portabilidade resultantes da expressão correta do formato dos dados. Se você não fizer isso, o conhecimento de que o primeiro campo é o nome do arquivo e o segundo é o tamanho deve ser mantido em outro lugar. Isso economiza memória, mas custa legibilidade e portabilidade. O que vai custar mais dinheiro à sua empresa?

Quanto à questão imutável, lembre-se de imutável não significa inútil diante da mudança. Isso significa que precisamos pegar mais memória, fazer a alteração em uma cópia e usar a nova cópia. Isso não é gratuito, mas muitas vezes não é um disjuntor. Usamos cordas imutáveis ​​para mudar as coisas o tempo todo.

Outra consideração é a extensibilidade. Quando você armazena dados apenas em posição, sem codificar informações de formato, é condenado a apenas uma herança, o que realmente não passa de prática de concatenar campos adicionais após os campos estabelecidos. Posso definir um terceiro campo para ser a data de criação e ainda ser compatível com o seu formato, pois defino primeiro e segundo da mesma maneira.

No entanto, o que não posso fazer é reunir dois formatos definidos independentemente, com alguns campos sobrepostos, outros não, armazená-los em um formato e ser útil para coisas que só sabem sobre um ou outro formato.

Para fazer isso, preciso codificar as informações de formato desde o início. Eu preciso dizer "este campo é o nome do arquivo". Isso permite herança múltipla.

Você provavelmente está acostumado a herança apenas sendo expressa no contexto de objetos, mas as mesmas idéias funcionam para formatos de dados porque, bem, os objetos são armazenados em formatos de dados. É exatamente o mesmo problema.

Portanto, use o que achar mais provável. Busco flexibilidade, a menos que consiga apontar um bom motivo para não fazê-lo.

candied_orange
fonte
3
Para ser sincero, duvido que qualquer pessoa que não tenha certeza entre usar um formato dentro ou fora da banda tenha requisitos de desempenho tão rígidos que precisaria usar um formato fora da banda
Alexander - Reinstate Monica
2
@ Alexander muito verdade. Prefiro ensinar as pessoas sobre o assunto para que elas entendam o que estão vendo quando confrontadas com soluções fora da banda. Os formatos binários costumam fazer isso por motivos de ofuscação. Nem todo mundo quer ser portátil. Por razões de desempenho, se realmente importa, considere a compactação antes de recorrer à banda externa.
candied_orange
Lembre-se de que o OP está usando Python, portanto, eles provavelmente não estão muito preocupados com o desempenho. A maioria dos códigos de alto nível deve ser escrita com a legibilidade em mente primeiro; Otimização prematura é a raiz de todo o mal.
Dagrooms
@ Dagrooms não odeiam Python. Ele funciona bem em muitos casos. Mas, caso contrário, concordo com tudo o que você disse. Meu objetivo era dizer "É por isso que as pessoas fazem isso. Eis por que você provavelmente não se importa".
candied_orange
@CandiedOrange Não estou odiando o idioma, uso-o no meu trabalho diário. Não gosto da maneira como as pessoas o usam.
Dagrooms
7

Eu usaria uma classe com duas propriedades. file.sizeé melhor que um file[1]ou outro file["size"].

Simples é melhor que complexo.

JacquesB
fonte
No caso de alguém está se perguntando: Por JSONs geradoras, ambos trabalham igualmente bem: file = Filesize(filename='stuff.txt', size=222)e filetup = ("stuff.txt", 222)ambos geram o mesmo JSON: json.dumps(file)e json.dumps(filetup)resultam em:'["stuff.txt", 222]'
Juha Untinen
5

Os nomes de arquivo são exclusivos? Nesse caso, você pode descartar completamente a lista e usar apenas um dicionário puro para todos os arquivos. por exemplo (um site hipotético)

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

etc ...

Agora, você não recebe "nome" e "tamanho", apenas usa chave e valor, mas geralmente isso é mais natural. YMMV.

Se você realmente deseja um "tamanho" para maior clareza ou precisa de mais de um valor para o arquivo, então:

{ 
   "/index.html" : { "size": 5467, "mime_type" : "foo" },
   "/about.html" : { "size": 3425, "mime_type" : "foo" }
   "/css/main.css" : { "size": 9876, "mime_type" : "bar" }
}
user949300
fonte
0

Em python, dicionário é objeto mutável. Por outro lado, tupla é objeto imutável.

se você precisar alterar a chave do dicionário, par de valores frequentemente ou sempre. Eu sugiro dicionário para usar.

se você tiver dados fixos / estáticos, sugiro usar tupla.

# 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'

Mas, não é possível alterar os dados da tupla usando o operador de atribuição.

Aprofundar Patel
fonte