2010-10-07 15 views
7

Ho seguente codice in uno script pythonchiusura dei file correttamente aperti con urllib2.urlopen()

try: 
    # send the query request 
    sf = urllib2.urlopen(search_query) 
    search_soup = BeautifulSoup.BeautifulStoneSoup(sf.read()) 
    sf.close() 
    except Exception, err: 
    print("Couldn't get programme information.") 
    print(str(err)) 
    return 

Sono preoccupato, perché se io incontro un errore sul sf.read(), quindi sf.clsoe() non è chiamato. Ho provato a inserire sf.close() in un blocco finally, ma se c'è un'eccezione su urlopen(), non c'è alcun file da chiudere e ho riscontrato un'eccezione nel blocco finally!

Allora ho provato

try: 
    with urllib2.urlopen(search_query) as sf: 
     search_soup = BeautifulSoup.BeautifulStoneSoup(sf.read()) 
    except Exception, err: 
    print("Couldn't get programme information.") 
    print(str(err)) 
    return 

ma questo ha sollevato un errore di sintassi non valida sulla linea with.... Come posso gestire al meglio questo, mi sento stupido!

Come commentatori hanno fatto notare, sto usando PyS60 che è Python 2.5.4

+2

L'istruzione "with" è disponibile solo in Python 2.6 o in 2.5 se si inserisce 'from __future__ import with_statement' nella parte superiore del file. Non ricordo bene quale versione Python PyS60 implementa ma potrebbe essere 2.5? –

+0

è 2.5.4. l'importazione è un buon punto :) – Habbie

risposta

6

Perché non provare a chiudere sf, e passando, se non esiste ?

import urllib2 
try: 
    search_query = 'http://blah' 
    sf = urllib2.urlopen(search_query) 
    search_soup = BeautifulSoup.BeautifulStoneSoup(sf.read()) 
except urllib2.URLError, err: 
    print(err.reason) 
finally: 
    try: 
     sf.close() 
    except NameError: 
     pass 
+0

Sapevo che mi mancava qualcosa di ovvio, tris annidato! La tua soluzione è molto elegante, grazie! – fearoffours

0

Sembra che il problema è più profondo di quanto pensassi - this forum thread indica urllib2 non implementa with fino a dopo Python 2.6, e forse non fino a 3,1

+0

Questo è vero. Sono su Python 2.7 (commentando nel 2013) e non sembra funzionare, quindi sto riscrivendo qualcosa scritto in origine per Python3 in Python2 e sono costretto a riscrivere tutto il mio 'con urllib.urlopen (source) come f: 'dichiarazioni. – erewok

8
finally: 
    if sf: sf.close() 
16

avrei usato contextlib.closing (in combinazione con da __future__ with_statement di importazione per le vecchie versioni di Python):

from contextlib import closing 

with closing(urllib2.urlopen('http://blah')) as sf: 
    search_soup = BeautifulSoup.BeautifulStoneSoup(sf.read()) 

O, se si vuole evitare l'istruzione with:

try: 
    sf = None 
    sf = urllib2.urlopen('http://blah') 
    search_soup = BeautifulSoup.BeautifulStoneSoup(sf.read()) 
finally: 
    if sf: 
     sf.close() 

Non altrettanto elegante.

0

Si potrebbe creare il proprio opener generici URL:

from contextlib import contextmanager 

@contextmanager 
def urlopener(inURL): 
    """Open a URL and yield the fileHandle then close the connection when leaving the 'with' clause.""" 
    fileHandle = urllib2.urlopen(inURL) 
    try:  yield fileHandle 
    finally: fileHandle.close() 

allora si potrebbe quindi utilizzare la sintassi dalla tua domanda iniziale:

with urlopener(theURL) as sf: 
    search_soup = BeautifulSoup.BeautifulSoup(sf.read()) 

Questa soluzione consente una netta separazione delle preoccupazioni. Si ottiene una sintassi urlopener generica e pulita che gestisce la complessità della chiusura corretta della risorsa, indipendentemente dagli errori che si verificano sotto la clausola with.

0

Perché non utilizzare più tentativi/eccetto i blocchi?

try: 
    # send the query request 
    sf = urllib2.urlopen(search_query) 
except urllib2.URLError as url_error: 
    sys.stderr.write("Error requesting url: %s\n" % (search_query,)) 
    raise 

try: 
    search_soup = BeautifulSoup.BeautifulStoneSoup(sf.read()) 
except Exception, err: # Maybe catch more specific Exceptions here 
    sys.stderr.write("Couldn't get programme information from url: %s\n" % (search_query,)) 
    raise # or return as in your original code 
finally: 
    sf.close() 
0

Se urlopen() dispone di un'eccezione, prenderlo e chiamare la funzione del eccezione close(), in questo modo:

try: 
    req = urllib2.urlopen(url) 
    req.close() 
    print 'request {0} ok'.format(url) 
except urllib2.HTTPError, e: 
    e.close() 
    print 'request {0} failed, http code: {1}'.format(url, e.code) 
except urllib2.URLError, e: 
    print 'request {0} error, error reason: {1}'.format(url, e.reason) 

l'eccezione è anche un oggetto di risposta completa, è possibile vedere questo problema messaggio: http://bugs.jython.org/issue1544