Source

diveintopython3-it / descrizioni.html

Full commit
<!DOCTYPE html>
<meta charset=utf-8>
<title>Descrizioni - Immersione in Python 3</title>
<!--[if IE]><script src=j/html5.js></script><![endif]-->
<link rel=stylesheet href=dip3.css>
<style>
body{counter-reset:h1 3}
</style>
<link rel=stylesheet media='only screen and (max-device-width: 480px)' href=mobile.css>
<link rel=stylesheet media=print href=print.css>
<meta name=viewport content='initial-scale=1.0'>
<form action=http://www.google.com/cse><div><input type=hidden name=cx value=014021643941856155761:l5eihuescdw><input type=hidden name=ie value=UTF-8>&nbsp;<input type=search name=q size=25 placeholder="powered by Google&trade;">&nbsp;<input type=submit name=root value=Search></div></form>
<p>You are here: <a href=index.html>Inizio</a> <span class=u>&#8227;</span> <a href=indice.html#descrizioni>Immersione in Python 3</a> <span class=u>&#8227;</span>
<p id=level>Livello di difficoltà: <span class=u title=principiante>&#x2666;&#x2666;&#x2662;&#x2662;&#x2662;</span>
<h1>Descrizioni</h1>
<blockquote class=q>
<p><span class=u>&#x275D;</span> La nostra immaginazione è tesa al massimo; non, come nelle storie fantastiche, per immaginare cose che in realtà non esistono, ma proprio per comprendere ciò che davvero esiste. <span class=u>&#x275E;</span><br>&mdash; <a href=http://it.wikiquote.org/wiki/Richard_Feynman>Richard Feynman</a>
</blockquote>
<p id=toc>&nbsp;
<h2 id=divingin>Immersione!</h2>
<p class=f>Esaminando i linguaggi di programmazione, si nota che ognuno possiede una particolare funzionalità che, pur essendo complessa per natura, è stata resa intenzionalmente semplice. Quando state imparando un nuovo linguaggio potreste non riuscire a riconoscerla, perché i linguaggi che conoscete non la rendono altrettanto semplice, occupati come sono a semplificare qualche altra funzione. Questo capitolo vi insegnerà le descrizioni di lista, le descrizioni di dizionario e le descrizioni di insieme: tre concetti correlati basati su un&#8217;unica tecnica molto potente. Ma prima vorrei fare una breve digressione per parlarvi di due moduli che vi aiuteranno a navigare nel vostro file system locale.

<p class=a>&#x2042;

<h2 id=os>Lavorare con i file e le directory</h2>

<p>Python 3 include un modulo chiamato <code>os</code>, che sta per &#8220;sistema operativo&#8221;. Il <a href=http://docs.python.org/3.1/library/os.html>modulo <code>os</code></a> contiene una pletora di funzioni per ottenere informazioni su&nbsp;&mdash;&nbsp;e, in alcuni casi, manipolare&nbsp;&mdash;&nbsp;directory locali, file, processi e variabili d&#8217;ambiente. Python fa del suo meglio per offrire una <abbr>API</abbr> unificata attraverso <a href=installare-python.html>tutti i sistemi operativi supportati</a> in modo che i vostri programmi possano funzionare su qualsiasi computer utilizzando la più piccola quantità possibile di codice specifico per la piattaforma.

<h3 id=getcwd>La directory di lavoro corrente</h3>

<p>Se avete appena cominciato a lavorare con Python, vi ritroverete a passare molto tempo nella <a href=installare-python.html#idle>Shell Python</a>. In tutto il libro, vedrete esempi che si sviluppano nel modo seguente.

<ol>
<li>Uno dei moduli contenuti nella cartella <a href=esempi/><code>esempi</code></a> viene importato.
<li>Si invoca una funzione appartenente a quel modulo.
<li>Il risultato della funzione viene spiegato.
</ol>

<aside>C&#8217;è sempre una directory di lavoro corrente.</aside>

<p>Se non conoscete la directory di lavoro corrente, il passo n°1 probabilmente fallirà con un errore di tipo <code>ImportError</code>. Questo avviene perché Python cercherà il modulo di esempio nel <a href=il-vostro-primo-programma-python.html#importsearchpath>percorso di ricerca per le importazioni</a>, ma non lo troverà perché la cartella <code>esempi</code> non è una delle directory contenute nel percorso di ricerca. Per risolvere questo problema, avete due alternative.

<ol>
<li>Aggiungere la cartella <code>esempi</code> al percorso di ricerca per le importazioni.
<li>Cambiare la directory di lavoro corrente impostandola alla cartella <code>esempi</code>.
</ol>

<p>La directory di lavoro corrente è una proprietà invisibile che Python mantiene in memoria tutto il tempo. C&#8217;è sempre una directory di lavoro corrente, sia che vi troviate nella Shell Python, o che eseguiate il vostro programma Python dalla riga di comando, oppure che invochiate uno script <abbr>CGI</abbr> Python su un server web in rete da qualche parte.

<p>Il modulo <code>os</code> contiene due funzioni per lavorare con la directory di lavoro corrente.

<pre class=screen>
<a><samp class=p>>>> </samp><kbd class=pp>import os</kbd>                                            <span class=u>&#x2460;</span></a>
<a><samp class=p>>>> </samp><kbd class=pp>print(os.getcwd())</kbd>                                   <span class=u>&#x2461;</span></a>
<samp>C:\Python31</samp>
<a><samp class=p>>>> </samp><kbd class=pp>os.chdir('/Users/pilgrim/diveintopython3/esempi')</kbd>    <span class=u>&#x2462;</span></a>
<a><samp class=p>>>> </samp><kbd class=pp>print(os.getcwd())</kbd>                                   <span class=u>&#x2463;</span></a>
<samp>C:\Users\pilgrim\diveintopython3\esempi</samp></pre>
<ol>
<li>Il modulo <code>os</code> è incluso in Python, quindi potete importarlo ovunque e in ogni momento.
<li>Usate la funzione <code>os.getcwd()</code> per ottenere la directory di lavoro corrente. Quando eseguite la Shell Python grafica, la directory di lavoro corrente viene impostata alla directory in cui si trova il file eseguibile della Shell Python. Su Windows, questa ubicazione dipende da dove avete installato Python; la directory di installazione predefinita è <code>C:\Python31</code>. Se eseguite la Shell Python dalla riga di comando, la directory di lavoro corrente viene impostata alla directory in cui vi trovavate quando avete invocato <code>python3</code>.
<li>Usate la funzione <code>os.chdir()</code> per cambiare la directory di lavoro corrente.
<li>Quando ho invocato la funzione <code>os.chdir()</code>, ho usato un percorso in stile Linux (con i caratteri di slash, senza la lettera del disco) anche se sono su Windows. Questo è uno dei casi in cui Python cerca di nascondere le differenze tra i sistemi operativi.
</ol>

<h3 id=ospath>Lavorare con i nomi di file e directory</h3>

<p>Visto che stiamo parlando di directory voglio mostrarvi il modulo <code>os.path</code>, che contiene funzioni per manipolare nomi di file e directory.

<pre class=screen>
<samp class=p>>>> </samp><kbd class=pp>import os</kbd>
<a><samp class=p>>>> </samp><kbd class=pp>print(os.path.join('/Users/pilgrim/diveintopython3/esempi/', 'humansize.py'))</kbd>              <span class=u>&#x2460;</span></a>
<samp>/Users/pilgrim/diveintopython3/esempi/humansize.py</samp>
<a><samp class=p>>>> </samp><kbd class=pp>print(os.path.join('/Users/pilgrim/diveintopython3/esempi', 'humansize.py'))</kbd>               <span class=u>&#x2461;</span></a>
<samp>/Users/pilgrim/diveintopython3/esempi\humansize.py</samp>
<a><samp class=p>>>> </samp><kbd class=pp>print(os.path.expanduser('~'))</kbd>                                                             <span class=u>&#x2462;</span></a>
<samp>c:\Users\pilgrim</samp>
<a><samp class=p>>>> </samp><kbd class=pp>print(os.path.join(os.path.expanduser('~'), 'diveintopython3', 'esempi', 'humansize.py'))</kbd>  <span class=u>&#x2463;</span></a>
<samp>c:\Users\pilgrim\diveintopython3\esempi\humansize.py</samp></pre>
<ol>
<li>La funzione <code>os.path.join()</code> costruisce un nome di percorso a partire da uno o più nomi di percorso parziali. In questo caso, non fa altro che concatenare stringhe.
<li>In questo caso leggermente meno elementare, la funzione <code>os.path.join()</code> aggiungerà un carattere di slash ulteriore al nome di percorso prima di unirlo al nome del file. Il carattere è un backslash anziché uno slash, perché ho realizzato questo esempio su Windows. Se replicate questo esempio su Linux o Mac OS X, vedrete uno slash. Evitate di armeggiare con i caratteri di slash: usate sempre <code>os.path.join()</code> e lasciate che sia Python a scegliere quelli giusti.
<li>La funzione <code>os.path.expanduser()</code> espanderà un nome di percorso che usa il carattere <code>~</code> per rappresentare la directory personale dell&#8217;utente corrente. Questa operazione funziona su tutte le piattaforme dove gli utenti hanno una directory personale, comprese Linux, Mac OS X e Windows. Il percorso restituito non ha uno slash finale, ma la funzione <code>os.path.join()</code> non se ne preoccupa.
<li>Combinando queste tecniche, potete facilmente costruire nomi di percorso per directory e file che si trovano nella directory personale dell&#8217;utente. La funzione <code>os.path.join()</code> può accettare un numero qualsiasi di argomenti. Ero felicissimo quando l&#8217;ho scoperto, perché <code>aggiungiSlashSeNecessario()</code> è una di quelle piccole funzioni stupide che mi tocca sempre scrivere quando costruisco il mio armamentario di utilità in un nuovo linguaggio. <em>Non</em> dovete scrivere questa piccola funzione stupida in Python, perché alcune persone intelligenti se ne sono già occupate per voi.
</ol>

<p>Il modulo <code>os.path</code> contiene anche funzioni per suddividere nomi di percorso completi, nomi di directory e nomi di file nelle loro parti costituenti.

<pre class=screen>
<samp class=p>>>> </samp><kbd class=pp>pathname = '/Users/pilgrim/diveintopython3/esempi/humansize.py'</kbd>
<a><samp class=p>>>> </samp><kbd class=pp>os.path.split(pathname)</kbd>                                        <span class=u>&#x2460;</span></a>
<samp class=pp>('/Users/pilgrim/diveintopython3/esempi', 'humansize.py')</samp>
<a><samp class=p>>>> </samp><kbd class=pp>(dirname, filename) = os.path.split(pathname)</kbd>                  <span class=u>&#x2461;</span></a>
<a><samp class=p>>>> </samp><kbd class=pp>dirname</kbd>                                                        <span class=u>&#x2462;</span></a>
<samp class=pp>'/Users/pilgrim/diveintopython3/esempi'</samp>
<a><samp class=p>>>> </samp><kbd class=pp>filename</kbd>                                                       <span class=u>&#x2463;</span></a>
<samp class=pp>'humansize.py'</samp>
<a><samp class=p>>>> </samp><kbd class=pp>(shortname, extension) = os.path.splitext(filename)</kbd>            <span class=u>&#x2464;</span></a>
<samp class=p>>>> </samp><kbd class=pp>shortname</kbd>
<samp class=pp>'humansize'</samp>
<samp class=p>>>> </samp><kbd class=pp>extension</kbd>
<samp class=pp>'.py'</samp></pre>
<ol>
<li>La funzione <code>split()</code> suddivide un nome di percorso completo e restituisce una tupla contenente il percorso e il nome di file.
<li>Ricordate quando ho detto che potevate usare un <a href=tipi-di-dato-nativi.html#multivar>assegnamento multivariabile</a> per restituire più di un valore da una funzione? La funzione <code>os.path.split()</code> fa esattamente questo. Se assegnate il valore restituito dalla funzione <code>split()</code> a una tupla di due variabili, ogni variabile riceve il valore del corrispondente elemento contenuto nella tupla restituita.
<li>La prima variabile, <var>dirname</var>, riceve il primo elemento della tupla restituita dalla funzione <code>os.path.split()</code>, cioè il percorso del file.
<li>La seconda variabile, <var>filename</var>, riceve il valore del secondo elemento della tupla restituita dalla funzione <code>os.path.split()</code>, cioè il nome del file.
<li>Il modulo <code>os.path</code> contiene anche la funzione <code>os.path.splitext()</code>, che suddivide un nome di file e restituisce una tupla contenente il nome del file e l&#8217;estensione del file. Potete usare la tecnica già vista per assegnare ogni valore a variabili separate.
</ol>

<h3 id=glob>Elencare il contenuto delle directory</h3>

<p>Il modulo <code>glob</code> è un altro strumento incluso nella libreria standard di Python. Vi fornisce un modo facile per ottenere programmaticamente il contenuto di una directory e usa quelle combinazioni di caratteri chiamate wildcard che potreste aver già visto lavorando sulla riga di comando.

<aside>Il modulo <code>glob</code> usa le wildcard tipiche della shell.</aside>

<pre class=screen>
<samp class=p>>>> </samp><kbd class=pp>os.chdir('/Users/pilgrim/diveintopython3/')</kbd>
<samp class=p>>>> </samp><kbd class=pp>import glob</kbd>
<a><samp class=p>>>> </samp><kbd class=pp>glob.glob('esempi/*.xml')</kbd>                  <span class=u>&#x2460;</span></a>
<samp class=pp>['esempi\\feed-broken.xml',
 'esempi\\feed-ns0.xml',
 'esempi\\feed.xml']</samp>
<a><samp class=p>>>> </samp><kbd class=pp>os.chdir('esempi/')</kbd>                        <span class=u>&#x2461;</span></a>
<a><samp class=p>>>> </samp><kbd class=pp>glob.glob('*test*.py')</kbd>                     <span class=u>&#x2462;</span></a>
<samp class=pp>['alphameticstest.py',
 'pluraltest1.py',
 'pluraltest2.py',
 'pluraltest3.py',
 'pluraltest4.py',
 'pluraltest5.py',
 'pluraltest6.py',
 'romantest1.py',
 'romantest10.py',
 'romantest2.py',
 'romantest3.py',
 'romantest4.py',
 'romantest5.py',
 'romantest6.py',
 'romantest7.py',
 'romantest8.py',
 'romantest9.py']</samp></pre>
<ol>
<li>Il modulo <code>glob</code> prende una wildcard e restituisce il percorso di tutti i file e le directory che corrispondono alla wildcard. In questo esempio, la wildcard è un percorso di directory più &#8220;<code>*.xml</code>&#8221;, che corrisponde a tutti i file <code>.xml</code> nella sottodirectory <code>esempi</code>.
<li>Ora impostiamo la directory di lavoro corrente alla sottodirectory <code>esempi</code>. La funzione <code>os.chdir()</code> può accettare nomi di percorso relativi.
<li>Potete includere molteplici wildcard nel vostro pattern di tipo glob. Questo esempio trova tutti i file nella directory di lavoro corrente che terminano con l&#8217;estensione <code>.py</code> e contengono la parola <code>test</code> da qualche parte nel loro nome.
</ol>

<h3 id=osstat>Ottenere metadati sui file</h3>

<p>Tutti i file system moderni memorizzano alcuni metadati su ogni file: la data di creazione, la data dell&#8217;ultima modifica, la dimensione del file, e così via. Python vi fornisce una singola <abbr>API</abbr> per accedere a questi metadati. Non avete bisogno di aprire il file, tutto quello che vi serve è il suo nome.

<pre class=screen>
<samp class=p>>>> </samp><kbd class=pp>import os</kbd>
<a><samp class=p>>>> </samp><kbd class=pp>print(os.getcwd())</kbd>                 <span class=u>&#x2460;</span></a>
<samp>c:\Users\pilgrim\diveintopython3\esempi</samp>
<a><samp class=p>>>> </samp><kbd class=pp>metadata = os.stat('feed.xml')</kbd>     <span class=u>&#x2461;</span></a>
<a><samp class=p>>>> </samp><kbd class=pp>metadata.st_mtime</kbd>                  <span class=u>&#x2462;</span></a>
<samp class=pp>1247520344.9537716</samp>
<a><samp class=p>>>> </samp><kbd class=pp>import time</kbd>                        <span class=u>&#x2463;</span></a>
<a><samp class=p>>>> </samp><kbd class=pp>time.localtime(metadata.st_mtime)</kbd>  <span class=u>&#x2464;</span></a>
<samp class=pp>time.struct_time(tm_year=2009, tm_mon=7, tm_mday=13, tm_hour=17,
  tm_min=25, tm_sec=44, tm_wday=0, tm_yday=194, tm_isdst=1)</samp>
</pre>
<ol>
<li>La directory di lavoro corrente è la cartella <code>esempi</code>.
<li><code>feed.xml</code> è un file che si trova nella cartella <code>esempi</code>. Invocare la funzione <code>os.stat()</code> restituisce un oggetto che contiene diversi tipi di metadati sul file.
<li><code>st_mtime</code> è la data di modifica, ma è in un formato che non è molto utile. (Tecnicamente, rappresenta il numero di secondi trascorsi dal 1° gennaio 1970. Non sto scherzando.)
<li>Il modulo <code>time</code> è parte della libreria standard di Python e contiene funzioni di conversione tra differenti rappresentazioni temporali, funzioni per formattare i valori temporali in stringhe e funzioni per lavorare con i fusi orari.
<li>La funzione <code>time.localtime()</code> converte un valore temporale espresso come numero di secondi trascorsi dal 1° gennaio 1970 (come rappresentato dalla proprietà <code>st_mtime</code> restituita dalla funzione <code>os.stat()</code>) in una struttura più utile contenente anno, mese, giorno, ora, minuto, secondo, e così via. La modifica più recente a questo file è stata effettuata il 13 giugno 2009, attorno alle 17:25.
</ol>

<pre class=screen>
# continua dall'esempio precedente
<a><samp class=p>>>> </samp><kbd class=pp>metadata.st_size</kbd>                              <span class=u>&#x2460;</span></a>
<samp class=pp>3070</samp>
<samp class=p>>>> </samp><kbd class=pp>import humansize</kbd>
<a><samp class=p>>>> </samp><kbd class=pp>humansize.approximate_size(metadata.st_size)</kbd>  <span class=u>&#x2461;</span></a>
<samp class=pp>'3.0 KiB'</samp></pre>
<ol>
<li>La funzione <code>os.stat()</code> restituisce anche la dimensione di un file, nella proprietà <code>st_size</code>. Il file <code>feed.xml</code> è di <code>3070</code> byte.
<li>Potete passare la proprietà <code>st_size</code> alla <a href=il-vostro-primo-programma-python.html#divingin>funzione <code>approximate_size()</code></a>.
</ol>

<h3 id=abspath>Costruire nomi di percorso assoluti</h3>

<p>Nella <a href=#osstat>sezione precedente</a> avete visto come la funzione <code>glob.glob()</code> restituisca una lista di nomi di percorso relativi. Il primo esempio mostrava nomi di percorso come <code>'esempi\feed.xml'</code> e il secondo esempio mostrava nomi di percorso relativi ancora più brevi come <code>'romantest1.py'</code>. Fino a quando rimanete nella stessa directory di lavoro corrente, questi nomi di percorso relativi funzioneranno per aprire file e ottenere metadati sui file. Ma se volete costruire un nome di percorso assoluto&nbsp;&mdash;&nbsp;cioè uno che includa i nomi di tutte le directory fino alla directory radice o alla lettera del disco&nbsp;&mdash;&nbsp;allora avrete bisogno della funzione <code>os.path.realpath()</code>.

<pre class=screen>
<samp class=p>>>> </samp><kbd class=pp>import os</kbd>
<samp class=p>>>> </samp><kbd class=pp>print(os.getcwd())</kbd>
<samp>c:\Users\pilgrim\diveintopython3\esempi</samp>
<samp class=p>>>> </samp><kbd class=pp>print(os.path.realpath('feed.xml'))</kbd>
<samp>c:\Users\pilgrim\diveintopython3\esempi\feed.xml</samp></pre>

<p class=a>&#x2042;

<h2 id=listcomprehension>Descrizioni di lista</h2>

<aside>Una descrizione di lista può contenere una espressione Python qualsiasi.</aside>

<p>Una <dfn>descrizione di lista</dfn> fornisce un modo compatto di correlare una lista con un&#8217;altra lista applicando una funzione a ogni elemento della prima lista.

<pre class=screen>
<samp class=p>>>> </samp><kbd class=pp>a_list = [1, 9, 8, 4]</kbd>
<a><samp class=p>>>> </samp><kbd class=pp>[elem * 2 for elem in a_list]</kbd>           <span class=u>&#x2460;</span></a>
<samp class=pp>[2, 18, 16, 8]</samp>
<a><samp class=p>>>> </samp><kbd class=pp>a_list</kbd>                                  <span class=u>&#x2461;</span></a>
<samp class=pp>[1, 9, 8, 4]</samp>
<a><samp class=p>>>> </samp><kbd class=pp>a_list = [elem * 2 for elem in a_list]</kbd>  <span class=u>&#x2462;</span></a>
<samp class=p>>>> </samp><kbd class=pp>a_list</kbd>
<samp class=pp>[2, 18, 16, 8]</samp></pre>
<ol>
<li>Per capire il senso di questa espressione, esaminatela da destra verso sinistra. <var>a_list</var> è la lista di partenza. L&#8217;interprete Python percorre <var>a_list</var> un elemento alla volta, assegnando temporaneamente il valore di ogni elemento alla variabile <var>elem</var>. Poi, Python applica la funzione <code><var>elem</var> * 2</code> e aggiunge quel risultato in coda alla lista restituita.
<li>Una descrizione di lista crea una nuova lista e non modifica la lista originale.
<li>Assegnare il risultato di una descrizione di lista alla variabile che contiene la lista di partenza non crea problemi. Python costruisce la nuova lista in memoria e quando la descrizione di lista è completa ne assegna il risultato alla variabile originale.
</ol>

<p>Una descrizione di lista può contenere un&#8217;espressione Python qualsiasi, incluse le funzioni del modulo <code>os</code> per manipolare file e directory.

<pre class=screen>
<samp class=p>>>> </samp><kbd class=pp>import os, glob</kbd>
<a><samp class=p>>>> </samp><kbd class=pp>glob.glob('*.xml')</kbd>                                 <span class=u>&#x2460;</span></a>
<samp class=pp>['feed-broken.xml', 'feed-ns0.xml', 'feed.xml']</samp>
<a><samp class=p>>>> </samp><kbd class=pp>[os.path.realpath(f) for f in glob.glob('*.xml')]</kbd>  <span class=u>&#x2461;</span></a>
<samp class=pp>['c:\\Users\\pilgrim\\diveintopython3\\esempi\\feed-broken.xml',
 'c:\\Users\\pilgrim\\diveintopython3\\esempi\\feed-ns0.xml',
 'c:\\Users\\pilgrim\\diveintopython3\\esempi\\feed.xml']</samp>
</pre>
<ol>
<li>Questo restituisce una lista di tutti i file <code>.xml</code> nella directory di lavoro corrente.
<li>Questa descrizione di lista prende la lista di file <code>.xml</code> e la trasforma in una lista di nomi di percorso completi.
</ol>

<p>Le descrizioni di lista possono anche filtrare gli elementi, producendo un risultato che può essere più piccolo della lista originale.

<pre class=screen>
<samp class=p>>>> </samp><kbd class=pp>import os, glob</kbd>
<a><samp class=p>>>> </samp><kbd class=pp>[f for f in glob.glob('*.py') if os.stat(f).st_size > 6000]</kbd>  <span class=u>&#x2460;</span></a>
<samp class=pp>['pluraltest6.py',
 'romantest10.py',
 'romantest6.py',
 'romantest7.py',
 'romantest8.py',
 'romantest9.py']</samp>
</pre>
<ol>
<li>Per filtrare una lista potete includere una clausola <code>if</code> in fondo alla descrizione di lista. L&#8217;espressione dopo la parola chiave <code>if</code> verrà valutata per ogni elemento della lista. Se l&#8217;espressione viene valutata a <code>True</code>, l&#8217;elemento verrà incluso nel risultato. Questa descrizione di lista esamina la lista di tutti i file <code>.py</code> nella directory corrente e l&#8217;espressione <code>if</code> filtra quella lista controllando se la dimensione di ogni file è più grande di <code>6000</code> byte. Ci sono sei file con questa caratteristica, quindi la descrizione di lista restituisce una lista di sei nomi di file.
</ol>

<p>Tutti gli esempi di descrizioni di lista visti finora hanno utilizzato espressioni semplici&nbsp;&mdash;&nbsp;moltiplica un numero per una costante, invoca una singola funzione, o semplicemente restituisci gli elementi della lista originale (dopo averli filtrati). Ma non c&#8217;è alcun limite alla complessità delle descrizioni di lista.

<pre class=screen>
<samp class=p>>>> </samp><kbd class=pp>import os, glob</kbd>
<a><samp class=p>>>> </samp><kbd class=pp>[(os.stat(f).st_size, os.path.realpath(f)) for f in glob.glob('*.xml')]</kbd>            <span class=u>&#x2460;</span></a>
<samp class=pp>[(3074, 'c:\\Users\\pilgrim\\diveintopython3\\esempi\\feed-broken.xml'),
 (3386, 'c:\\Users\\pilgrim\\diveintopython3\\esempi\\feed-ns0.xml'),
 (3070, 'c:\\Users\\pilgrim\\diveintopython3\\esempi\\feed.xml')]</samp>
<samp class=p>>>> </samp><kbd class=pp>import humansize</kbd>
<a><samp class=p>>>> </samp><kbd class=pp>[(humansize.approximate_size(os.stat(f).st_size), f) for f in glob.glob('*.xml')]</kbd>  <span class=u>&#x2461;</span></a>
<samp class=pp>[('3.0 KiB', 'feed-broken.xml'),
 ('3.3 KiB', 'feed-ns0.xml'),
 ('3.0 KiB', 'feed.xml')]</samp></pre>
<ol>
<li>Questa descrizione di lista trova tutti i file <code>.xml</code> nella directory di lavoro corrente, ottiene la dimensione di ogni file (invocando la funzione <code>os.stat()</code>) e costruisce una tupla contenente la dimensione del file e il percorso assoluto di ogni file (invocando la funzione <code>os.path.realpath()</code>).
<li>Questa descrizione lavora a partire da quella precedente per invocare la <a href=il-vostro-primo-programma-python.html#divingin>funzione <code>approximate_size()</code></a> passando la dimensione di ogni file <code>.xml</code>.
</ol>

<p class=a>&#x2042;

<h2 id=dictionarycomprehension>Descrizioni di dizionario</h2>

<p>Una <dfn>descrizione di dizionario</dfn> è come una descrizione di lista, ma costruisce un dizionario invece di una lista.

<pre class=screen>
<samp class=p>>>> </samp><kbd class=pp>import os, glob</kbd>
<a><samp class=p>>>> </samp><kbd class=pp>metadata = [(f, os.stat(f)) for f in glob.glob('*test*.py')]</kbd>    <span class=u>&#x2460;</span></a>
<a><samp class=p>>>> </samp><kbd class=pp>metadata[0]</kbd>                                                     <span class=u>&#x2461;</span></a>
<samp class=pp>('alphameticstest.py', nt.stat_result(st_mode=33206, st_ino=0, st_dev=0,
 st_nlink=0, st_uid=0, st_gid=0, st_size=2509, st_atime=1247520344,
 st_mtime=1247520344, st_ctime=1247520344))</samp>
<a><samp class=p>>>> </samp><kbd class=pp>metadata_dict = {f:os.stat(f) for f in glob.glob('*test*.py')}</kbd>  <span class=u>&#x2462;</span></a>
<a><samp class=p>>>> </samp><kbd class=pp>type(metadata_dict)</kbd>                                             <span class=u>&#x2463;</span></a>
<samp>&lt;class 'dict'></samp>
<a><samp class=p>>>> </samp><kbd class=pp>list(metadata_dict.keys())</kbd>                                      <span class=u>&#x2464;</span></a>
<samp class=pp>['romantest8.py', 'pluraltest1.py', 'pluraltest2.py', 'pluraltest5.py',
 'pluraltest6.py', 'romantest7.py', 'romantest10.py', 'romantest4.py',
 'romantest9.py', 'pluraltest3.py', 'romantest1.py', 'romantest2.py',
 'romantest3.py', 'romantest5.py', 'romantest6.py', 'alphameticstest.py',
 'pluraltest4.py']</samp>
<a><samp class=p>>>> </samp><kbd class=pp>metadata_dict['alphameticstest.py'].st_size</kbd>                     <span class=u>&#x2465;</span></a>
<samp class=pp>2509</samp></pre>
<ol>
<li>Questa non è una descrizione di dizionario, ma una <a href=#listcomprehension>descrizione di lista</a>. Trova tutti i file <code>.py</code> il cui nome contiene la parola <code>test</code>, poi costruisce una tupla contenente il nome del file e i metadati del file (invocando la funzione <code>os.stat()</code>).
<li>Ogni elemento della lista risultante è una tupla.
<li>Questa è una descrizione di dizionario. La sintassi è simile a quella per una descrizione di lista, con due differenze. Primo, è racchiusa tra parentesi graffe anziché parentesi quadre. Secondo, invece di una singola espressione per ogni elemento, contiene due espressioni separate da un carattere di due punti. L&#8217;espressione prima dei due punti (<code>f</code> in questo esempio) è la chiave del dizionario, l&#8217;espressione dopo i due punti (<code>os.stat(f)</code> in questo esempio) è il valore.
<li>Una descrizione di dizionario restituisce un dizionario.
<li>Le chiavi di questo particolare dizionario sono semplicemente i nomi di file restituiti dall&#8217;invocazione di <code>glob.glob('*test*.py')</code>.
<li>Il valore associato a ogni chiave è il valore restituito dalla funzione <code>os.stat()</code>. Questo significa che possiamo &#8220;cercare&#8221; un file tramite il nome per ottenere i suoi metadati. Una delle parti dei metadati è <code>st_size</code>, la dimensione del file. Il file <code>alphameticstest.py</code> è di <code>2509</code> byte.
</ol>

<p>Come con le descrizioni di lista, potete includere una clausola <code>if</code> in una descrizione di dizionario per filtrare la sequenza in ingresso sulla base di un&#8217;espressione che viene valutata per ogni elemento.

<pre class=screen>
<samp class=p>>>> </samp><kbd class=pp>import os, glob, humansize</kbd>
<a><samp class=p>>>> </samp><kbd class=pp>metadata_dict = {f:os.stat(f) for f in glob.glob('*')}</kbd>                                  <span class=u>&#x2460;</span></a>
<a><samp class=p>>>> </samp><kbd class=pp>humansize_dict = {os.path.splitext(f)[0]:humansize.approximate_size(meta.st_size) \     </kbd>
<samp class=p>... </samp><kbd class=pp>                  for f, meta in metadata_dict.items() if meta.st_size > 6000}</kbd>          <span class=u>&#x2461;</span></a>
<a><samp class=p>>>> </samp><kbd class=pp>list(humansize_dict.keys())</kbd>                                                             <span class=u>&#x2462;</span></a>
<samp class=pp>['romantest9', 'romantest8', 'romantest7', 'romantest6', 'romantest10', 'pluraltest6']</samp>
<a><samp class=p>>>> </samp><kbd class=pp>humansize_dict['romantest9']</kbd>                                                            <span class=u>&#x2463;</span></a>
<samp class=pp>'6.5 KiB'</samp></pre>
<ol>

<li>Questa descrizione di dizionario costruisce una lista di tutti i file nella directory di lavoro corrente (<code>glob.glob('*')</code>), ottiene i metadati di ogni file (<code>os.stat(f)</code>) e costruisce un dizionario le cui chiavi sono i nomi dei file e i cui valori sono i metadati di ogni file.
<li>Questa descrizione di dizionario viene costruita a partire dalla descrizione precedente, filtrandola per escludere i file più piccoli di <code>6000</code> byte (<code>if meta.st_size > 6000</code>) e usando poi la lista filtrata per costruire un dizionario le cui chiavi sono i nomi dei file senza l&#8217;estensione (<code>os.path.splitext(f)[0]</code>) e i cui valori sono le dimensioni approssimate di ogni file (<code>humansize.approximate_size(meta.st_size)</code>).
<li>Come avete visto nell&#8217;esempio precedente, ci sono sei file con le caratteristiche richieste, quindi ci sono sei file in questo dizionario.
<li>Il valore corrispondente a ogni chiave è la stringa restituita dalla funzione <code>approximate_size()</code>.
</ol>

<h3 id=stupiddicttricks>Altra roba divertente da fare con le descrizioni di dizionario</h3>

<p>Ecco un trucco da usare con le descrizioni di dizionario che un giorno potrebbe esservi utile: scambiare le chiavi e i valori di un dizionario.

<pre class=screen>
<samp class=p>>>> </samp><kbd class=pp>a_dict = {'a': 1, 'b': 2, 'c': 3}</kbd>
<samp class=p>>>> </samp><kbd class=pp>{value:key for key, value in a_dict.items()}</kbd>
<samp class=pp>{1: 'a', 2: 'b', 3: 'c'}</samp></pre>

<p>Naturalmente, questo funziona solo se i valori del dizionario sono immutabili, come stringhe o tuple. Se provate a farlo con un dizionario che contiene liste, il trucco fallirà in maniera piuttosto vistosa.

<pre class=screen>
<samp class=p>>>> </samp><kbd class=pp>a_dict = {'a': [1, 2, 3], 'b': 4, 'c': 5}</kbd>
<samp class=p>>>> </samp><kbd class=pp>{value:key for key, value in a_dict.items()}</kbd>
<samp class=traceback>Traceback (most recent call last):
  File "&lt;stdin>", line 1, in &lt;module>
  File "&lt;stdin>", line 1, in &lt;dictcomp>
TypeError: unhashable type: 'list'</samp></pre>

<p class=a>&#x2042;

<h2 id=setcomprehension>Descrizioni di insieme</h2>

<p>Non va dimenticato che anche gli insiemi hanno la propria sintassi di descrizione. Questa sintassi è notevolmente simile a quella per le descrizioni di dizionario. L&#8217;unica differenza è che gli insiemi contengono solo valori invece di coppie chiave:valore.

<pre class=screen>
<samp class=p>>>> </samp><kbd class=pp>a_set = set(range(10))</kbd>
<samp class=p>>>> </samp><kbd class=pp>a_set</kbd>
<samp class=pp>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}</samp>
<a><samp class=p>>>> </samp><kbd class=pp>{x ** 2 for x in a_set}</kbd>           <span class=u>&#x2460;</span></a>
<samp class=pp>{0, 1, 4, 81, 64, 9, 16, 49, 25, 36}</samp>
<a><samp class=p>>>> </samp><kbd class=pp>{x for x in a_set if x % 2 == 0}</kbd>  <span class=u>&#x2461;</span></a>
<samp class=pp>{0, 8, 2, 4, 6}</samp>
<a><samp class=p>>>> </samp><kbd class=pp>{2**x for x in range(10)}</kbd>         <span class=u>&#x2462;</span></a>
<samp class=pp>{32, 1, 2, 4, 8, 64, 128, 256, 16, 512}</samp>
</pre>
<ol>
<li>Le descrizioni di insieme possono prendere in ingresso un insieme. Questa descrizione di insieme calcola i quadrati dell&#8217;insieme dei numeri da 0 a <code>9</code>.
<li>Come con le descrizioni di lista e di dizionario, le descrizioni di insieme possono contenere una clausola <code>if</code> per filtrare gli elementi prima di restituirli nell&#8217;insieme dei risultati.
<li>Le descrizioni di insieme non hanno necessariamente bisogno di prendere in ingresso un insieme, ma possono accettare qualsiasi sequenza.
</ol>

<p class=a>&#x2042;

<h2 id=furtherreading>Letture di approfondimento</h2>
<ul>
<li><a href=http://docs.python.org/3.1/library/os.html>Il modulo <code>os</code></a>
<li><a href=http://www.doughellmann.com/PyMOTW/os/><code>os</code>&nbsp;&mdash;&nbsp;Accesso portabile alle funzioni specifiche dei sistemi operativi</a>
<li><a href=http://docs.python.org/3.1/library/os.path.html>Il modulo <code>os.path</code></a>
<li><a href=http://www.doughellmann.com/PyMOTW/ospath/><code>os.path</code>&nbsp;&mdash;&nbsp;Manipolazione dei nomi di file indipendente dalla piattaforma</a>
<li><a href=http://docs.python.org/3.1/library/glob.html>Il modulo <code>glob</code></a>
<li><a href=http://www.doughellmann.com/PyMOTW/glob/><code>glob</code>&nbsp;&mdash;&nbsp;Corrispondenze di pattern per i nomi di file</a>
<li><a href=http://docs.python.org/3.1/library/time.html>Il modulo <code>time</code></a>
<li><a href=http://www.doughellmann.com/PyMOTW/time/><code>time</code>&nbsp;&mdash;&nbsp;Funzioni per manipolare l&#8217;orario</a>
<li><a href=http://docs.python.org/3.1/tutorial/datastructures.html#list-comprehensions>Descrizioni di lista</a>
<li><a href=http://docs.python.org/3.1/tutorial/datastructures.html#nested-list-comprehensions>Descrizioni di lista annidate</a>
<li><a href=http://docs.python.org/3.1/tutorial/datastructures.html#looping-techniques>Tecniche di attraversamento</a>
</ul>
<p class=v><a href=tipi-di-dato-nativi.html rel=prev title='indietro a &#8220;Tipi di dato nativi&#8221;'><span class=u>&#x261C;</span></a> <a href=stringhe.html rel=next title='avanti a &#8220;Stringhe&#8221;'><span class=u>&#x261E;</span></a>
<p class=c>&copy; 2001&ndash;10 <a href=informazioni-sul-libro.html>Mark Pilgrim</a><br>
&copy; 2009&ndash;10 <a href=informazioni-sulla-traduzione.html>Giulio Piancastelli</a> per la traduzione italiana
<script src=j/jquery.js></script>
<script src=j/prettify.js></script>
<script src=j/dip3.js></script>