2010-10-07 13 views
7

He siguiente código en un script en Pythoncierre de archivos correctamente abrieron 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 

Me preocupa porque si encuentro un error en sf.read(), entonces sf.clsoe() no se llama. He intentado poner sf.close() en un bloque finally, pero si hay una excepción en urlopen() entonces no hay archivo para cerrar y me encuentro con una excepción en el bloque finally!

Entonces me trataron

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 

pero esto eleva un error de sintaxis no válida en la línea de with.... ¿Cómo puedo manejar esto mejor, me siento estúpido?

Como comentaristas han señalado, estoy usando PyS60 que es Python 2.5.4

+2

La declaración "con" solo está disponible en Python 2.6, o en 2.5 si coloca 'from __future__ import with_statement' en la parte superior de su archivo. No recuerdo bien qué Python versión PyS60 implementa pero podría ser 2.5? –

+0

es 2.5.4. la importación es un buen punto :) – Habbie

Respuesta

6

¿Por qué no intente cerrar sf, y que pasa si no existe ?

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

¡Sabía que me faltaba algo obvio, ensayos anidados! Su solución es muy elegante, ¡gracias! – fearoffours

0

Parece que el problema es más profundo de lo que pensaba - this forum thread indica urllib2 no implementa with hasta después de Python 2.6, y posiblemente no hasta 3.1

+0

Esto es cierto. Estoy en Python 2.7 (comentando en 2013) y parece que no funciona, así que estoy reescribiendo algo escrito originalmente para Python3 en Python2 y me veo forzado a reescribir todo mi 'con urllib.urlopen (fuente) como f: 'declaraciones. – erewok

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

me gustaría utilizar contextlib.closing (en combinación con la importación de __future__ with_statement para las versiones antiguas de Python):

from contextlib import closing 

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

O, si se quiere evitar la sentencia with:

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

Aunque no del todo elegante.

0

Se puede crear su propio abridor de URL genérica:

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() 

entonces se podría entonces utilizar la sintaxis de su pregunta original:

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

Esta solución le da una clara separación de las preocupaciones. Obtiene una sintaxis genérica de urlopener que maneja las complejidades de cerrar correctamente el recurso independientemente de los errores que ocurran debajo de su cláusula con.

0

¿Por qué no utilizar bloques múltiples try/except?

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

Si urlopen() tiene una excepción, cogerlo y llamar a la función de la excepción close(), así:

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) 

excepción es también un objeto de respuesta completa, se puede ver este tema mensaje: http://bugs.jython.org/issue1544

Cuestiones relacionadas