Utilidades de Python

En esta sección, veremos algunos de los numerosos módulos de utilidad estándar de Python para resolver problemas comunes.

Sistema de archivos: os, os.path, cierre

Los módulos *os* y *os.path* incluyen muchas funciones para interactuar con el sistema de archivos. El módulo *shutil* puede copiar archivos.

  • Documentos sobre el módulo OS
  • filenames = os.listdir(dir): lista de nombres de archivos en esa ruta de acceso al directorio (sin incluir . y ..). Los nombres de los archivos son solo los nombres del directorio, no sus rutas absolutas.
  • os.path.join(dir, nombre de archivo): dado un nombre de archivo de la lista anterior, utilízalo para combinarlos y el nombre de archivo a fin de crear una ruta de acceso
  • os.path.abspath(ruta): si se indica una ruta de acceso, se muestra un formato absoluto, por ejemplo, /home/nick/foo/bar.html
  • os.path.dirname(ruta), os.path.basename(ruta) -- en función de dir/foo/bar.html, muestra el dirname "dir/foo" y el nombre base "bar.html"
  • os.path.exists(path): es verdadero si existe
  • os.mkdir(dir_path): crea un dir, os.makedirs(dir_path) realiza todos los dir necesarios en esta ruta
  • call.copy(source-path, dest-path): copia un archivo (los directorios de rutas de dest. deben existir).
## Example pulls filenames from a dir, prints their relative and absolute paths
def printdir(dir):
  filenames = os.listdir(dir)
  for filename in filenames:
    print(filename)  ## foo.txt
    print(os.path.join(dir, filename)) ## dir/foo.txt (relative to current dir)
    print(os.path.abspath(os.path.join(dir, filename))) ## /home/nick/dir/foo.txt

La exploración de un módulo funciona bien con las funciones integradas help() y dir() de Python. En el intérprete, haz una "importación os" y, luego, usa estos comandos para ver lo que está disponible en el módulo: dir(os), help(os.listdir), dir(os.path), help(os.path.dirname).

Ejecución de procesos externos: subproceso

El módulo *subprocess* es una manera sencilla de ejecutar un comando externo y capturar su resultado.

  • documentos del módulo de subprocesos
  • output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) -- ejecuta el comando, espera a que salga y muestra su texto de resultado. El comando se ejecuta con su resultado estándar y su error estándar combinados en el texto de salida. Si falla, arroja un CalledProcessError.
  • Si deseas tener más control sobre la ejecución del subproceso, consulta la clase subprocess.popen
  • También hay un subprocess.call(cmd) simple que ejecuta el comando, vuelca su resultado en el resultado y muestra su código de error. Esto funciona si desea ejecutar el comando, pero no necesita capturar los resultados en sus estructuras de datos de Python.
import subprocess

## Given a dir path, run an external 'ls -l' on it --
## shows how to call an external program
def listdir(dir):
  cmd = 'ls -l ' + dir
  print("Command to run:", cmd)   ## good to debug cmd before actually running it
  (status, output) = subprocess.getstatusoutput(cmd)
  if status:    ## Error case, print the command's output to stderr and exit
    sys.stderr.write(output)
    sys.exit(status)
  print(output)  ## Otherwise do something with the command's output

Excepciones

Una excepción representa un error en el tiempo de ejecución que detiene la ejecución normal en una línea determinada y transfiere el control al código de manejo de errores. En esta sección, solo se presentan los usos más básicos de las excepciones. Por ejemplo, un error de tiempo de ejecución podría ser que una variable utilizada en el programa no tiene un valor (ValueError .. probablemente lo hayas visto alguna vez) o un error de operación de apertura de archivo porque no existe un archivo (IOError). Obtén más información en el instructivo de excepciones y consulta la lista completa de excepciones.

Sin código de manejo de errores (como lo hicimos hasta ahora), una excepción de tiempo de ejecución simplemente detiene el programa con un mensaje de error. Ese es un buen comportamiento predeterminado, y lo has visto muchas veces. Puedes agregar una estructura de "prueba/excepto" a tu código para manejar excepciones, como la siguiente:

  try:
    ## Either of these two lines could throw an IOError, say
    ## if the file does not exist or the read() encounters a low level error.
    f = open(filename, 'rb')
    data = f.read()
    f.close()
  except IOError:
    ## Control jumps directly to here if any of the above lines throws IOError.
    sys.stderr.write('problem reading:' + filename)
  ## In any case, the code then continues with the line after the try/except

La sección try: incluye el código que podría arrojar una excepción. La sección "excepto:" contiene el código que se debe ejecutar si hay una excepción. Si no hay una excepción, se omite la sección "excepto:" (es decir, ese código es solo para el manejo de errores, no el caso "normal" del código). Puedes obtener un puntero al objeto de la excepción con la sintaxis "excepto IOError como e: .." (e apunta al objeto de excepción).

HTTP: urllib y urlparse

El módulo *urllib.request* proporciona la recuperación de URL, lo que hace que una URL parezca un archivo en el que puedes leer. El módulo *urlparse* puede separar y crear URL.

  • Documentos del módulo de urllib.request
  • ufile = urllib.request.urlopen(url) -- muestra un archivo similar a un objeto para esa URL.
  • text = ufile.read() -- puede leer desde allí, como un archivo (readlines(), etc. también funciona)
  • info = ufile.info() -- La metainformación de esa solicitud. info.gettype() es el tipo de MIME, p.ej., "text/html"
  • baseurl = ufile.geturl() -- Obtiene la url "base" para la solicitud, que puede ser diferente de la original debido a los redireccionamientos.
  • urllib.request.urlretrieve(url, nombre del archivo): Descarga los datos de las URL a la ruta del archivo especificada.
  • urllib.parse.urljoin(baseurl, url): si una URL puede estar completa y la URL base de la página de la que proviene, se muestra una URL completa. Usa geturl() arriba para proporcionar la URL base.

Todas las excepciones están en urllib.error.

from urllib.request import urlopen

## Given a url, try to retrieve it. If it's text/html,
## print its base url and its text.
def wget(url):
  ufile = urlopen(url)  ## get file-like object for url
  info = ufile.info()   ## meta-info about the url content
  if info.get_content_type() == 'text/html':
    print('base url:' + ufile.geturl())
    text = ufile.read()  ## read all its text
    print(text)

El código anterior funciona bien, pero no incluye la administración de errores si una URL no funciona por algún motivo. Esta es una versión de la función que agrega lógica de prueba/salvo para imprimir un mensaje de error si la operación de URL falla.

Si urlopen() parece estar suspendido, es posible que tu sistema no permita el acceso directo a algunas direcciones HTTP. Para verificarlo, intenta recuperar la misma URL con wget o curl. Si estos programas también fallan, deberás recuperar el contenido de http a través de un servicio de proxy. La configuración del acceso mediante proxies no se aborda en este instructivo.

## Version that uses try/except to print an error message if the
## urlopen() fails.
def wget2(url):
  try:
    ufile = urlopen(url)
    if ufile.info().get_content_type() == 'text/html':
      print(ufile.read())
  except IOError:
    print('problem reading url:', url)

Ejercicio

Para practicar el material del sistema de archivos y los comandos externos, consulta el Ejercicio especial de copia. Para practicar el material de urllib, consulta Log Puzzle Exercise.