Quando usare un dizionario vs tupla in Python


31

L'esempio specifico in mente è un elenco di nomi di file e le loro dimensioni. Non riesco a decidere se ciascun elemento nell'elenco deve essere del modulo {"filename": "blabla", "size": 123}o solo ("blabla", 123). Un dizionario mi sembra più logico perché accedere alle dimensioni, ad esempio, file["size"]è più esplicativo di file[1]... ma non lo so per certo. Pensieri?


Come addendum, considera il disimballaggio della tupla , se ti preoccupi della leggibilità delle tuple - fname, file_size = file, dove i dati sono la tua tupla sopra, eliminerebbero file[1]e sostituirli file_size. Naturalmente questo si basa su una buona documentazione.
nlsdfnbch,

2
Dipende dalla struttura di dati che stai costruendo e come intendi accedervi? (per nome file? per indice? entrambi?) È solo una variabile / struttura di dati usa e getta, o aggiungerai forse altri elementi (/ attributi) oltre alle dimensioni? La struttura deve ricordare un ordine? vuoi ordinare l'elenco delle dimensioni o accedervi per posizione (ad es. "top-n file più grandi / più piccoli")? A seconda di ciò, la risposta "migliore" potrebbe essere dict, OrderedDict, namedtuple, semplice vecchio elenco o una propria classe personalizzata. Hai bisogno di più contesto da parte tua.
smci,

Risposte:


78

Vorrei usare un namedtuple:

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

Ora puoi usare file.sizee file.filenamenel tuo programma, che è IMHO il modulo più leggibile. Nota namedtuplecrea oggetti immutabili come le tuple e sono più leggeri dei dizionari, come descritto qui .


1
Grazie, buona idea, non ne ho mai sentito parlare prima d'ora (sono abbastanza novizio a Python). Domanda: cosa succede se qualcun altro nel codice definisce anche la stessa "classe", possibilmente in modo leggermente diverso. ad esempio, in qualche altro file sorgente, il collega Bob avevaFilesize = namedtuple('Filesize', 'filepath kilobytes')
user949300

Puoi anche usare il attrsmodulo molto bello (puoi trovarlo attraverso pipo semplicemente cercarlo), che ti consente di avere comodità sintattiche molto simili alla tupla nominata, ma può darti la mutabilità (ma può anche essere reso immutabile). La principale differenza funzionale è che le attrsclassi create non sono paragonabili alle semplici tuple, come namedtuplefanno le altre.
mtraceur,

3
@DocBrown Python non ha alcun concetto di dichiarazioni. class, defe =tutti sovrascrivono tutti gli usi precedenti. repl.it
Challenger5

@ Challenger5: hai ragione, errore mio, quindi la risposta corretta è: conta la definizione più recente, nessun errore dal runtime di Python, ma comunque un comportamento simile a quello di qualsiasi altra variabile.
Doc Brown,

8
Si noti che namedtupleè essenzialmente una dichiarazione abbreviata per un nuovo tipo con attributi immutabili. Ciò significa che la risposta è effettivamente "Né a tuplené a dict, ma un object". +1
jpmc26

18

{"nome file": "blabla", "size": 123} o semplicemente ("blabla", 123)

Questa è l'annosa domanda se codificare il formato / schema in banda o fuori banda.

Scambia un po 'di memoria per ottenere la leggibilità e la portabilità che deriva dall'esprimere il formato dei dati direttamente nei dati. Se non lo fai, devi sapere che il primo campo è il nome del file e il secondo è che la dimensione deve essere mantenuta altrove. Ciò consente di risparmiare memoria ma costa leggibilità e portabilità. Quale costerà alla tua azienda più soldi?

Per quanto riguarda l'immutabile problema, ricorda che l'immutabile non significa inutile di fronte al cambiamento. Significa che dobbiamo acquisire più memoria, apportare la modifica in una copia e utilizzare la nuova copia. Non è gratuito ma spesso non è un affare. Usiamo stringhe immutabili per cambiare le cose continuamente.

Un'altra considerazione è l'estensibilità. Quando memorizzi i dati solo in posizione, senza codificare le informazioni sul formato, sei condannato a un'unica eredità, che in realtà non è altro che la pratica di concatenare campi aggiuntivi dopo i campi stabiliti. Posso definire un terzo campo per essere la data di creazione ed essere ancora compatibile con il tuo formato poiché definisco il primo e il secondo allo stesso modo.

Tuttavia, ciò che non posso fare è riunire due formati definiti in modo indipendente che hanno alcuni campi sovrapposti, altri no, archiviarli in un formato e renderli utili a cose che conoscono solo l'uno o l'altro formato.

Per fare ciò ho bisogno di codificare le informazioni sul formato dall'inizio. Devo dire "questo campo è il nome del file". Ciò consente l'ereditarietà multipla.

Probabilmente sei abituato all'eredità espressa solo nel contesto degli oggetti, ma le stesse idee funzionano per i formati di dati perché, beh, gli oggetti sono memorizzati in formati di dati. È esattamente lo stesso problema.

Quindi usa quello che ritieni abbia più probabilità di avere bisogno. Cerco flessibilità a meno che non possa indicare una buona ragione per non farlo.


3
Ad essere sincero, dubito che chiunque sia incerto sull'uso di un formato in-band o fuori-banda abbia requisiti di performance così stretti che avrebbe bisogno di usare un formato fuori banda
Alexander - Reinstate Monica,

2
@Alexander molto vero. Preferisco insegnare alle persone in modo che capiscano cosa stanno guardando quando si confrontano con soluzioni fuori banda. I formati binari lo fanno spesso per motivi di offuscamento. Non tutti vogliono essere portatili. Per quanto riguarda le prestazioni, se è davvero importante prendere in considerazione la compressione prima di ricorrere a fuori banda.
candied_orange,

Ricorda che OP utilizza Python, quindi probabilmente non sono troppo preoccupati per le prestazioni. La maggior parte del codice di alto livello dovrebbe essere scritta pensando innanzitutto alla leggibilità; l'ottimizzazione prematura è la radice di tutti i mali.
Dagrooms,

@Dagrooms non odiano Python. Si comporta bene in molti casi. Ma per il resto sono d'accordo con tutto quello che hai detto. Il mio punto era dire "Questo è il motivo per cui la gente lo fa. Ecco perché probabilmente non ti interessa".
candied_orange,

@CandiedOrange Non sto odiando la lingua, la uso nel mio lavoro quotidiano. Non mi piace il modo in cui le persone lo usano.
Dagrooms,

7

Vorrei usare una classe con due proprietà. file.sizeè più bello di file[1]o file["size"].

Semplice è meglio di complesso.


Nel caso qualcuno si stia chiedendo: per generare JSON, entrambi funzionano ugualmente bene: file = Filesize(filename='stuff.txt', size=222)ed filetup = ("stuff.txt", 222)entrambi generano lo stesso JSON: json.dumps(file)e json.dumps(filetup)risultano in:'["stuff.txt", 222]'
Juha Untinen,

5

I nomi dei file sono unici? In tal caso, è possibile eliminare completamente l'elenco e utilizzare un dizionario puro per tutti i file. ad es. (un sito Web ipotetico)

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

eccetera...

Ora, non ottieni "nome" e "dimensione", usi semplicemente chiave e valore, ma spesso questo è più naturale. YMMV.

Se vuoi davvero una "dimensione" per chiarezza o hai bisogno di più di un valore per il file, allora:

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

0

In Python, il dizionario è oggetto mutabile. Dall'altro lato, la tupla è un oggetto immutabile.

se devi cambiare la chiave del dizionario, abbina valore spesso o ogni volta. suggerisco dizionario da usare.

se hai dati fissi / statici, suggerisco di usare la 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'

Tuttavia, non è possibile modificare i dati della tupla utilizzando l'operatore di assegnazione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.