Please ignore secret bonuses. Secret tests do NOT award bonus. Max hw grade is 30+2 bonus efficiency

Do you need help?

creare n dizionari

Shangry_ (9930 points)
7 25 76
in Programmare in Python by (9.9k points)
closed by
Salve, vorrei sapere se è possibile creare una funzione che possa creare N dizionari, quindi inserendo il valore 8 crei 8 dizionari.
549 views
closed with the note: risposta data

2 Answers

Best answer
Ionut Cicio (5960 points)
2 2 43
by (6.0k points) 1 flag
selected by

La strategia migliore è quella di usare una list comprehension:

def generate_dicts(number):
    return [{} for _ in range(number)]

Il trattino basso è il nome della variabile, indica solo che sto creando una varibile che non uso effettivamente (non ne uso il valore), ma devo creare per forza (è uno standard che si usa in programmazione).

In seguito, spiego perché [{}] * 8 non funziona...

Hide & Seek (nascondino)!

Una delle cose che non mi piacciono di Python è il fatto che cerca di nascondere dettagli implementativi, generando comortamenti che a primo impatto, per un principiante (e a volte anche per chi ha un po' di esperienza), sembrano bizzarri o per nulla intuitivi... e, di fatto, per spiegare quello che succede dietro le quinte di certi comportamenti, serve un livello tecnico anche abbastanza elevato. Di fatto, per spiegare il problema del riferimento, bisogna comprendere 2 concetti per nulla banali: il layout in memoria (RAM) di un programma ed i puntatori...

Here we go again...

Per il layout in memoria ho già una un post su Q2A a https://q2a.di.uniroma1.it/26073/ricorsione-nell-hw2?course=hw2/homeworks/fondamenti-di-programmazione-22-23 (va letto il paragrafo "Stack & Heap" per capire il resto di questa risposta, anche perché copiare e incollare quello che ho già scritto non ha senso, oltre al fatto che Q2A ha 12000 caratteri di limite per le risposte se non sbaglio).

Pointers...

Pointers meme

Se sono riuscito magicamente a farti capire con l'altro articolo come funziona la memoria di un programma, o se conoscevi già l'argomento, è arrivato il momento di affrontare i famosi puntatori... Prima di continuare, bisogna specificare che ogni variabile, ogni ogetto etc... in memoria ha un indirizzo (che sarebbe un numero esadecimale, ho spiegato come funziona nell'ultimo paragrafo su https://q2a.di.uniroma1.it/26647/map-object-at-0x000002ca4a356490?course=hw1-optional/homework/programming-ay22-23)

Andiamo in biblioteca!

Il miglior modo per spiegare i puntatori è con l'esempio della biblioteca, non si scappa... Immaginiamo di essere i direttori di un'enorme biblioteca con migliaia di libri! Sono tantissimi, e molti sono grossi, pesanti e difficili da spostare... Decidiamo di organizzarli in ordine alfabetico usando il titolo perché più facile per i bibliotecari trovare libri. Dopo un po', ti accorgi che la maggior parte dei lettori, nei mesi invernali, non vuole cercare i libri in base al titolo, ma in base alla categoria preferita (fantasy, avventura, libri storici etc...), perché durante le vacanze leggono per piacere. Allora decidi di fare lo sforzo di riorganizzare tutti i libri nella biblioteca (per renderli più da trovare), anche se sono migliaia, sono pesanti grossi... Arriva maggio, ed i maturandi disperati cercano libri in base ai nomi degli autori più famosi... Questo è un problema bello grosso, perché dovresti riordinarli in ordine alfabeticon in base al nome e al cognome dell'autore!


Ci serve un modo intelligente per poter accontentare i bibliotecari, i lettori per piacere e gli studenti, come possiamo fare senza dover ogni volta spostare tutti i libri? enlightened

La soluzione è usare delle piccole schede di carta (siamo ancora prima dell'invenzione del computer), una scheda per ogni libro, in cui ci mettiamo il titolo, l'autore, le categorie, l'ISBN etc... e, l'informazione più importante: su quale scaffale sta il libro.

A questo punto abbiamo risolto il problema: queste schede si possono in maniera estremamente facile (sempre meglio che spostare un librone da un lato all'altro della nostra grande biblioteca), occupano poco spazio (c'entrano in un cassetto) ed è facile farne delle copie: quindi possiamo avere i libri organizzati in più modi diversi per accontentare tutti, basta fare più copie delle schede (non potrei copiare tutti i libri nella biblioteca solo per organizzarli in modo diverso).

Sostanzialmente, un puntatore non è altro che una scheda! I dizionari e le liste possono essere anche molto grossi (aka, libri molto grandi e pesanti), quindi difficili da spostare in memoria, ma possiamo creare una variabile con l'indirizzo di memoria del dizionario, perché per spostare quella variabile non ci vuole nulla (un indirizzo di memoria è un numero esadecimale piccolo). In questo modo possiamo spostare il puntatore (la variabile che contiene l'indirizzo di memoria, quindi "punta" al dizionario / lista / ogetto etc...) senza dover manipolare grandi quantità di memoria...

Per far riferimento all'articolo precedente, i puntatori vengono generalmente messi sulla stack (quindi la memoria veloce), e i dizionari e le liste (ma anche altri tipi di ogetti molto grossi) sulla heap (più lenta, ma capiente). Posso anche avere una collezione dentro alla heap con dentro puntatori... posso avere puntatori che puntano a puntatori che puntano a puntatori che puntano a puntatori che puntano a ogetti... (immagina come se in biblioteca la scheda ti indica lo scaffale 1, posizione 3, ma non trovi il libro: trovi una scheda che ti dice che il libro sta sullo scaffale 12, posizione 8 etc...)

La brutta notizia...

Python, a differenza di linguaggi come C, Rust e C++, gestisce i puntatori automaticamente, fa tutto lui di nascosto (il programmatore non decide se una variabile è un puntatore o meno), il che è buono, perché il programmatore non deve sapere cos'è un puntatore, o conoscere il layout del programma, e, soprattutto, si evita un sacco di errori (i puntatori sono frutto di tantissimi errori), ma ha lo svantaggio di generare comportamenti bizzarri (come quello di [{}] * 10).

Quindi?

Ora proviamo a spiegare cosa succede quando usiamo [{}] * 5. Python crea un dizionario nella heap, e nella lista come elemento ci mette il puntatore, quindi abbiamo qualcosa del tipo [puntatore a diz1] * 5; a questo punto, decide di espandere la lista, dando come risultato [puntatore a diz1, puntatore a diz1, puntatore a diz1, puntatore a diz1, puntatore a diz1], ovvero, 5 puntatori, ma tutti allo stesso identico dizionario! (è come se un lettore in biblioteca chiede 5 libri diversi, ma il bibliotecario gli indica per 5 volte lo scaffale e la posizione dello stesso libro... il lettore non è felice)

L'ordine delle operazioni, in questo caso, sarebbe: creo un dizionario dentro alla heap, e creo una lista con dentro il puntatore, e questa lista la espando mettendoci 5 volte il puntatore... bel casino...

d
danyspadea (4330 points)
1 4 25
by (4.3k points)
edited by
Non so se esistano funzioni del genere, ma per creare una lista di n dizionari ti basta fare:

lista = [{}]*n         e ti crea una lista con n dizionari.
Ionut Cicio (5960 points)
2 2 43
by (6.0k points)
edited by

Non funziona perché ti crea una lista in cui gli elementi si riferiscono allo stesso dizionario in memoria: in parole povere, vuol dire che se modifichi l'ottavo, ti modifica tutti gli altri. Non sono distinti fra di loro (se volete una spiegazione del perché succede questo, se chiedete posso darvela, ma ci vuole tempo).

d
danyspadea (4330 points)
1 4 25
by (4.3k points)
ah sì vero non ci avevo pensato
andrea.sterbini (208020 points)
756 1270 2377
by (208k points)
Vedi inizio della lezione sulle immagini