[Python] saluti e prima domanda sulle list comprhension

Enrico Franchi enrico.franchi a gmail.com
Dom 27 Gen 2008 18:10:19 CET


On Jan 27, 2008, at 5:34 PM, Java wrote:

> Salve a tutti, sono nuovo di questa mailing list e del pythone più in
> generale!

Io suggerirei di cambiare nome. <g> :)

> Prima di fare la domanda, preannuncio che mi sono occupato di questa
> cosa per un paio di giorni, e che essendo completamente niubbo con il
> python potrei aver fatto qualche cavolata :-D

Il che è naturale e altrimenti non posteresti qui. Aggiungo inoltre...  
la prima cavolata che i principianti fanno è applicare in toto  
strutture mentali che provengono da altri linguaggi.

> Veniamo alla nota dolente, devo fare un progetto per
> l'università(costruire una rete sociale di video di youtube) che
> comporta anche la scrittura di un piccolo crawler. Ho pensato di usare
> python sostanzialmente perché non lo conoscevo, e così approfitto
> dell'esame per imparare un nuovo linguaggio...

Interessante e ottimo proposito.

> Senza entrare troppo nei dettagli, ho fatto un thread che si occupa di
> fare il crawling di una pagina iterando per in base alla profondità di
> crawling.

Male: perché usare un thread? Ogni programmatore che si rende conto  
che spesso e volentieri i thread sono  la risposta sbagliata ad un non  
problema è una speranza per un futuro migliore.

Diciamocela tutta: se in Java si programma con i thread (a memoria  
condivisa), questo non vuole dire che debba essere buona pratica  
ovunque. Io in particolare per quello che fai tu userei multiprocesso.  
No: mento sapendo di mentire, forse userei un'altra cosa, ma non  
voglio complicarti ora la vita.


> def run ( self ):
>       #  lista temporanea
>       temp = []
>       # all'inizio la lista results contine l'url iniziale
>       results = [self.start_url]
>       #cast della profondita' in intero poiché la leggo da input
>       p = int(self.profondita)

brrr... ma così, dentro un thread prendi input da un utente?
Se l'input lo prendi fuori, falla *fuori* la conversione,  
eventualmente con un gestore di eccezioni.

>
>       # finche' la profondita' e' maggiore di zero, intero sulla lista
> temp eseguendo il
>       # parsing degli url trovati in essa
>       while(p > 0):
>           print "Thread lanciato con profondita: ", p
>           # copio i risultati attuali dentro la lista temp
>           # all'inizio conterrà solo un url
>           temp = results
>           print "ecco la lista TEMP:"
>           print  temp
>           [results.extend(self.parseUrl(video)) for video in temp]
>           print "finito ciclo while \n\n\n" # qua non ci arrivo  
> mai :-(
>           p-=1
>
> il problema è che in ogni caso non esce mai dalla list comphrension,
> eppure la lista temp contiene un solo url!

Ehm. Guarda che fai: temp = results. Per cui entrambi puntano allo  
stesso oggetto.
A questo punto hai un ciclo che per ogni video che trova in temp,  
aggiunge una cosa a results.
Ovvero a temp.

Una nota stilistica: l'uso che fai della list comprehension è IMHO  
sbagliato. Una list comprehension (pur essendo completamente generale)  
tipicamente viene usata per generare un nuovo array. Ha insomma un  
significato in cui il valore di ritorno della funzione ha *profondo*  
significato (e spesso questo nuovo array viene manipolato in seguito).

Tu invece la stai chiamando con un metodo che restituisce None. Il tuo  
codice anche se funzionasse, sarebbe 'bruttino'. Riscriviamolo con un  
for.

for video in temp:
     results.extend(self.parseUrl(vide))

Ecco... ora dovrebbe essere chiaro l'inghippo. Guarda questo codice  
(viene dall'interprete interattivo ipython):

In [58]: a = ["x"]

In [59]: for el in a:
    ....:   print a
    ....:   a.append(el)
    ....:
['x']
['x', 'x']
['x', 'x', 'x']
['x', 'x', 'x', 'x']
['x', 'x', 'x', 'x', 'x']
['x', 'x', 'x', 'x', 'x', 'x']
['x', 'x', 'x', 'x', 'x', 'x', 'x']

Questo è evidentemente e ovviamente sbagliato. Ora rendiamolo più  
simile al tuo codice:

In [62]: a = ["x"]

In [63]: b = a

In [65]: id(a) == id(b)
Out[65]: True

In [66]: print id(a), id(b)
7864368 7864368

In [67]: for el in a:
    ....:   print a
    ....:   b.append(el)
    ....:
['x']
['x', 'x']
['x', 'x', 'x']
['x', 'x', 'x', 'x']
['x', 'x', 'x', 'x', 'x']


Cioè tu iteri su qualcosa, ma aggiungi ad ogni iterazione un elemento.  
Ovvio che non termini.


> In pratica continua a ciclare come se ogni volta eseguisse temp =
> results, ma non capisco il perché...

Ti suggerisco di studiarti bene i fondamentali. Ti saresti reso conto  
che dopo avere fatto temp = results, entrambi sono riferimenti allo  
stesso oggetto. Da cui modificando attraverso uno quell'oggetto, la  
modifica la vedi anche sull'altro.





More information about the Python mailing list