Dict y archivo de Python

Tabla hash de dict

La estructura eficiente de la tabla hash de par clave-valor de Python se denomina "dict". El contenido de un diccionario se puede escribir como una serie de pares clave:valor dentro de llaves { }, p. ej., dict = {key1:value1, key2:value2, ... }. El "diccionario vacío" es solo un par vacío de llaves {}.

Para buscar o establecer un valor en un diccionario, se usan corchetes, p. ej., dict['foo'] busca el valor en la clave "foo". Las cadenas, los números y las tuplas funcionan como claves, y cualquier tipo puede ser un valor. Otros tipos pueden funcionar o no correctamente como claves (las cadenas y las tuplas funcionan de forma correcta, ya que son inmutables). Si buscas un valor que no está en el diccionario, se genera un KeyError. Usa "in" para verificar si la clave está en el diccionario o usa dict.get(clave), que muestra el valor o None si la clave no está presente (o get(clave, not-found) te permite especificar qué valor mostrar en el caso de que no se encuentre).

  ## Can build up a dict by starting with the empty dict {}
  ## and storing key/value pairs into the dict like this:
  ## dict[key] = value-for-that-key
  dict = {}
  dict['a'] = 'alpha'
  dict['g'] = 'gamma'
  dict['o'] = 'omega'

  print(dict) ## {'a': 'alpha', 'o': 'omega', 'g': 'gamma'}

  print(dict['a'])     ## Simple lookup, returns 'alpha'
  dict['a'] = 6       ## Put new key/value into dict
  'a' in dict         ## True
  ## print(dict['z'])                  ## Throws KeyError
  if 'z' in dict: print(dict['z'])     ## Avoid KeyError
  print(dict.get('z'))  ## None (instead of KeyError)

dict con claves 'a' 'o' 'g'

Un bucle for en un diccionario itera sobre sus claves de forma predeterminada. Las claves aparecerán en un orden arbitrario. Los métodos dict.keys() y dict.values() muestran listas de claves o valores de forma explícita. También hay un elemento items() que muestra una lista de tuplas (clave, valor), que es la forma más eficiente de examinar todos los datos de pares clave-valor en el diccionario. Todas estas listas se pueden pasar a la función sorted().

  ## By default, iterating over a dict iterates over its keys.
  ## Note that the keys are in a random order.
  for key in dict:
    print(key)
  ## prints a g o

  ## Exactly the same as above
  for key in dict.keys():
    print(key)

  ## Get the .keys() list:
  print(dict.keys())  ## dict_keys(['a', 'o', 'g'])

  ## Likewise, there's a .values() list of values
  print(dict.values())  ## dict_values(['alpha', 'omega', 'gamma'])

  ## Common case -- loop over the keys in sorted order,
  ## accessing each key/value
  for key in sorted(dict.keys()):
    print(key, dict[key])

  ## .items() is the dict expressed as (key, value) tuples
  print(dict.items())  ##  dict_items([('a', 'alpha'), ('o', 'omega'), ('g', 'gamma')])

  ## This loop syntax accesses the whole dict by looping
  ## over the .items() tuple list, accessing one (key, value)
  ## pair on each iteration.
  for k, v in dict.items(): print(k, '>', v)
  ## a > alpha    o > omega     g > gamma

Nota sobre la estrategia: Desde el punto de vista del rendimiento, el diccionario es una de tus mejores herramientas y debes usarlo siempre que sea posible para organizar los datos con facilidad. Por ejemplo, puedes leer un archivo de registro en el que cada línea comienza con una dirección IP y almacenar los datos en un diccionario con la dirección IP como clave y la lista de líneas en las que aparece como valor. Una vez que hayas leído el archivo completo, podrás buscar cualquier dirección IP y ver la lista de líneas de manera instantánea. El diccionario toma datos dispersos y los convierte en algo coherente.

Formato de dict

El operador % funciona de manera conveniente para sustituir valores de un diccionario en una cadena por nombre:

  h = {}
  h['word'] = 'garfield'
  h['count'] = 42
  s = 'I want %(count)d copies of %(word)s' % h  # %d for int, %s for string
  # 'I want 42 copies of garfield'

  # You can also use str.format().
  s = 'I want {count:d} copies of {word}'.format(h)

Supr

El operador "del" realiza eliminaciones. En el caso más simple, puede quitar la definición de una variable, como si no se hubiera definido esa variable. Del también se puede usar en elementos o secciones de listas para borrar esa parte de la lista y borrar entradas de un diccionario.

  var = 6
  del var  # var no more!

  list = ['a', 'b', 'c', 'd']
  del list[0]     ## Delete first element
  del list[-2:]   ## Delete last two elements
  print(list)      ## ['b']

  dict = {'a':1, 'b':2, 'c':3}
  del dict['b']   ## Delete 'b' entry
  print(dict)      ## {'a':1, 'c':3}

Archivos

La función open() abre y muestra un identificador de archivo que se puede usar para leer o escribir un archivo de la forma habitual. El código f = open('name', 'r') abre el archivo en la variable f, listo para operaciones de lectura, y usa f.close() cuando finaliza. En lugar de "r", usa "w" para escribir y "a" para agregar. El bucle for estándar funciona para archivos de texto y itera a través de las líneas del archivo (solo funciona para archivos de texto, no para archivos binarios). La técnica del bucle for es una forma simple y eficiente de ver todas las líneas de un archivo de texto:

  # Echo the contents of a text file
  f = open('foo.txt', 'rt', encoding='utf-8')
  for line in f:   ## iterates over the lines of the file
    print(line, end='')    ## end='' so print does not add an end-of-line char
                           ## since 'line' already includes the end-of-line.
  f.close()

Leer una línea a la vez tiene la ventaja de que no todo el archivo debe caber en la memoria a la vez, lo que es útil si quieres ver cada línea de un archivo de 10 gigabytes sin usar 10 gigabytes de memoria. El método f.readlines() lee todo el archivo en la memoria y muestra su contenido como una lista de líneas. El método f.read() lee todo el archivo en una sola cadena, lo que puede ser una forma práctica de abordar el texto de una sola vez, como con las expresiones regulares que veremos más adelante.

Para escribir, el método f.write(cadena) es la forma más sencilla de escribir datos en un archivo de salida abierto. También puedes usar “print” con un archivo abierto, como “print(cadena, archivo=f)”.

Archivos Unicode

Para leer y escribir archivos con codificación Unicode, usa un modo "t" y especifica explícitamente una codificación:


with open('foo.txt', 'rt', encoding='utf-8') as f:
  for line in f:
    # here line is a *unicode* string

with open('write_test', encoding='utf-8', mode='wt') as f:
    f.write('\u20ACunicode\u20AC\n') #  €unicode€
    # AKA print('\u20ACunicode\u20AC', file=f)  ## which auto-adds end='\n'

Desarrollo incremental del ejercicio

Cuando compiles un programa de Python, no lo escribas todo en un solo paso. En su lugar, identifica solo un primer hito, p. ej., "el primer paso es extraer la lista de palabras". Escribe el código para llegar a ese hito y, luego, imprime tus estructuras de datos en ese punto. Luego, puedes hacer un sys.exit(0) para que el programa no avance a las partes que aún no se completaron. Una vez que el código del evento importante funcione, puedes trabajar en el código del siguiente evento importante. Poder ver la copia impresa de tus variables en un estado puede ayudarte a pensar en cómo debes transformar esas variables para llegar al siguiente estado. Python es muy rápido con este patrón, lo que te permite hacer un pequeño cambio y ejecutar el programa para ver cómo funciona. Aprovecha ese tiempo de respuesta rápido para compilar tu programa en pequeños pasos.

Ejercicio: wordcount.py

Combina todo el material básico de Python (cadenas, listas, diccionarios, tuplas y archivos) y prueba el ejercicio de resumen wordcount.py en Ejercicios básicos.