domingo, 17 de mayo de 2015

Bases de datos documentales con TinyDB (y II)


En el capítulo anterior comenzamos el estudio de TinyDB, una base de datos documental dirigida a proyectos modestos bastante atractiva.

En dicho capítulo se expuso la forma de instalar el módulo Python necesario para trabajar con esta base de datos y se mostraron algunos ejemplos que ilustran algunas operaciones básicas.

A continuación, seguimos con más ejemplos para enseñar algunas características avanzadas de TinyDB. Para su realización recomendamos el entorno interactivo de Python o IPython.

Uso avanzado de TinyDB



Insertar múltiples registros de una vez


from tinydb import TinyDB, where
cielo = TinyDB('cielo.db')
constelacion = cielo.table('constelacion')
constelacion.insert_multiple([{'nombre':'Casiopea', 'abrev':'CAS'}, 
                              {'nombre':'Cefeo', 'abrev':'CEP'}]) # [1,2]
constelacion.all()

[{'abrev': 'CAS', 'nombre': 'Casiopea'}, {'abrev': 'CEP', 'nombre': 'Cefeo'}]

Insertar registros con campos diferentes


constelacion.insert({'nombre': 'Dragón', 
                    'abrev': 'DRA', 'sup': 1083})  # 3
constelacion.all()

[{'abrev': 'CAS', 'nombre': 'Casiopea'},
{'abrev': 'CEP', 'nombre': 'Cefeo'},
{'abrev': 'DRA', 'nombre': 'Dragón', 'sup': 1083}]

En una base de datos TinyDB todos los registros no tienen necesariamente que tener lo mismos campos.


Insertar un nuevo campo en un registro en una actualización


constelacion.update({'sup': 588}, where('nombre') == 'Cefeo')
constelacion.all()

[{'abrev': 'CAS', 'nombre': 'Casiopea'},
{'abrev': 'CEP', 'nombre': 'Cefeo', 'sup': 588},
{'abrev': 'DRA', 'nombre': 'Dragón', 'sup': 1083}]

Insertar múltiples registros insertando un nuevo campo con un valor autoincrementado


constelacion.insert_multiple({'obs': 'invierno', 
                             'indice': ind} for ind in range(5))
registros = constelacion.search(where('indice') != -1)

registros: [{'indice': 0, 'obs': 'invierno'},
{'indice': 1, 'obs': 'invierno'},
{'indice': 2, 'obs': 'invierno'},
{'indice': 3, 'obs': 'invierno'},
{'indice': 4, 'obs': 'invierno'}]

Actualizar borrando un campo de un registro que cumpla una condición


from tinydb.operations import delete, increment, decrement
constelacion.update(delete('indice'), where('indice') == 0)
constelacion.all()

[{'abrev': 'CAS', 'nombre': 'Casiopea'},
{'abrev': 'CEP', 'nombre': 'Cefeo', 'sup': 588},
{'abrev': 'DRA', 'nombre': 'Dragón', 'sup': 1083},
{'obs': 'invierno'},
{'indice': 1, 'obs': 'invierno'},
{'indice': 2, 'obs': 'invierno'},
{'indice': 3, 'obs': 'invierno'},
{'indice': 4, 'obs': 'invierno'}]

Actualizar incrementando en 1 el valor numérico de un campo


constelacion.update(increment('indice'), 
                    where('indice') != -1)
constelacion.all()

[{'abrev': 'CAS', 'nombre': 'Casiopea'},
{'abrev': 'CEP', 'nombre': 'Cefeo', 'sup': 588},
{'abrev': 'DRA', 'nombre': 'Dragón', 'sup': 1083},
{'obs': 'invierno'},
{'indice': 2, 'obs': 'invierno'},
{'indice': 3, 'obs': 'invierno'},
{'indice': 4, 'obs': 'invierno'},
{'indice': 5, 'obs': 'invierno'}]

Actualizar decrementando en 1 el valor numérico de un campo


constelacion.update(decrement('indice'), 
                    where('indice') != -1)
constelacion.all()

[{'abrev': 'CAS', 'nombre': 'Casiopea'},
{'abrev': 'CEP', 'nombre': 'Cefeo', 'sup': 588},
{'abrev': 'DRA', 'nombre': 'Dragón', 'sup': 1083},
{'obs': 'invierno'},
{'indice': 1, 'obs': 'invierno'},
{'indice': 2, 'obs': 'invierno'},
{'indice': 3, 'obs': 'invierno'},
{'indice': 4, 'obs': 'invierno'}]

Obtener el número de registros que tiene una tabla


num_registros = len(constelacion)
num_registros  # 8


Leer un registro que cumpla una condición (get)


registro = constelacion.get(where('obs') == 'invierno')
registro  # {'obs': 'invierno'}

Si no existen registros que cumplan la condición la función devuelve None:

registro = constelacion.get(where('obs') == 'verano')
registro  # None


Conocer si hay registros que cumplan una condición


hay_registros = constelacion.contains(where('sup') > 500)
hay_registros  # True

hay_registros = constelacion.contains(where('sup') > 1500)
hay_registros  # False


Contar los registros que cumplan una condición


num_registros = constelacion.count(where('sup') > 500)
num_registros  # 2


Consultar un registro por su ID


registro = constelacion.get(eid=3)
print(registro['nombre'], registro['abrev'])

Dragón DRA

Obtener el ID de un registro que cumpla una condición


registro = constelacion.get(where('nombre') == 'Cefeo')
registro.eid  # 2


Actualizar un campo de varios registros por sus ID


constelacion.update({'sup': 0}, eids=[7, 8])
constelacion.all()

[{'abrev': 'CAS', 'nombre': 'Casiopea'},
{'abrev': 'CEP', 'nombre': 'Cefeo', 'sup': 588},
{'abrev': 'DRA', 'nombre': 'Dragón', 'sup': 1083},
{'obs': 'invierno'},
{'indice': 1, 'obs': 'invierno'},
{'indice': 2, 'obs': 'invierno'},
{'indice': 3, 'obs': 'invierno', 'sup': 0},
{'indice': 4, 'obs': 'invierno', 'sup': 0}]

Borrar varios registros por su ID


constelacion.remove(eids=[4, 5, 6, 7, 8])
constelacion.all()

[{'abrev': 'CAS', 'nombre': 'Casiopea'},
{'abrev': 'CEP', 'nombre': 'Cefeo', 'sup': 588},
{'abrev': 'DRA', 'nombre': 'Dragón', 'sup': 1083}]

Consultar registros que no cumplan condición (NOT ~)


registros = constelacion.search(~(where('nombre') == 'Casiopea'))

registros: [{'abrev': 'CEP', 'nombre': 'Cefeo', 'sup': 588},
{'abrev': 'DRA', 'nombre': 'Dragón', 'sup': 1083},
{'obs': 'invierno'},
{'indice': 1, 'obs': 'invierno'},
{'indice': 2, 'obs': 'invierno'},
{'indice': 3, 'obs': 'invierno', 'sup': 0},
{'indice': 4, 'obs': 'invierno', 'sup': 0}]

Se obtienen todos los registros con nombre distinto a 'Casiopea' y aquellos que no tienen el campo nombre.


Consultar registros que cumplan una condición u otras (OR "|")


registros = constelacion.search((where('abrev') == 'CAS') \
            | (where('abrev') == 'CEP'))

registros: [{'abrev': 'CAS', 'nombre': 'Casiopea'},
{'abrev': 'CEP', 'nombre': 'Cefeo', 'sup': 588}]

Cada condición debe escribirse delimitada por paréntesis.

Consultar registros que cumplan más de una condición (AND "&")


registros = constelacion.search((where('nombre') != 'Cefeo') \
            & (where('sup') > 500))

registros: [{'abrev': 'DRA', 'nombre': 'Dragón', 'sup': 1083}]

Cada condición debe escribirse delimitada por paréntesis.

Consultar registros utilizando expresiones regulares


registros = constelacion.search(where('nombre').matches('^C'))
print(registros)  
# [{'abrev': 'CAS', 'nombre': 'Casiopea'}, 
# {'abrev': 'CEP', 'sup': 588, 'nombre': 'Cefeo'}]

registros = constelacion.search(where('nombre').contains('C+'))
print(registros)  
# [{'abrev': 'CAS', 'nombre': 'Casiopea'}, 
# {'abrev': 'CEP', 'sup': 588, 'nombre': 'Cefeo'}]


Consultar registros filtrando con una función


supmayora1000 = lambda superficie: superficie >= 1000
registros = constelacion.search(where('sup').test(supmayora1000))

registros: [{'abrev': 'DRA', 'sup': 1083, 'nombre': 'Dragón'}]

Insertar registros con campos anidados (diccionarios)


constelacion.purge()
# suprimimos todos los registros existentes 

constelacion.insert({'nombre': {'esp': 'Tauro', 'latin': 'Taurus'}, 
                     'caract': {'abrev': 'TAR', 'sup': 797}})
constelacion.insert({'nombre': {'esp': 'Cuervo', 'latin': 'Corvus'}, 
                     'caract': {'abrev': 'CRV', 'sup':184}})


Consultar registros con campos anidados (diccionarios)


registro = constelacion.search(where('nombre').has('latin') \
           == 'Corvus')

registro: [{'nombre': {'latin': 'Corvus', 'esp': 'Cuervo'}, 'caract': {'abrev': 'CRV', 'sup': 184}}]

Insertar registros con campos anidados (listas)


# suprimimos antes todos los registros existentes 
constelacion.purge()

constelacion.insert({'nombre': 'Tauro', 
                     'magnitud': [{'val': 0.87 }, 
                                  {'val': 1.68 }, 
                                  {'val': 3.5}]})

constelacion.insert({'nombre': 'Cuervo', 
                     'magnitud': [{'val': 4.02 }, 
                                  {'val': 2.65 }, 
                                  {'val': 2.58}] })


Consultar registros con campos anidados (listas) que al menos uno cumpla la condición


registros = constelacion.search(where('magnitud').any(where('val') \
            > 4))

registros: [{'magnitud': [{'val': 4.02}, {'val': 2.65}, {'val': 2.58}],
'nombre': 'Cuervo'}]

Consultar registros con campos anidados (listas) que todos cumplan la condición


registros = constelacion.search(where('magnitud').all(where('val') \
            > 2))

registros: [{'magnitud': [{'val': 4.02}, {'val': 2.65}, {'val': 2.58}],
'nombre': 'Cuervo'}]

Consultar registros con campos anidados (listas) que contengan algún valor de la lista


registros = constelacion.search(where('magnitud').any([{'val': 0.87},
                                                       {'val': 1.67}]))

registros: [{'magnitudes': [{'val': 0.87}, {'val': 1.68}, {'val': 3.5}],
'nombre': 'Tauro'}]

Crear base de datos utilizando la memoria convencional como soporte de almacenamiento


from tinydb.storages import MemoryStorage
cielo = TinyDB(storage=MemoryStorage)
constelacion = cielo.table('constelacion')
constelacion.insert({'nombre': 'Casiopea', 'abrev': 'CAS'})
constelacion.all()

[{'nombre': 'Casiopea', 'abrev': 'CAS'}]


Ir al índice del tutorial de Python

jueves, 14 de mayo de 2015

Bases de datos documentales con TinyDB (I)

Introducción


TinyDB es una base de datos documental idónea para proyectos pequeños o personales, fácil de usar y muy versátil.

Para trabajar con esta base de datos es necesario instalar los módulos escritos íntegramente en Python del alemán Markus Siemens. Dichos módulos no dependen de otro software para su funcionamiento y están disponibles tanto para Python 2.x como 3.x.

En relación al formato en que se guardan las bases de datos TinyDB indicar que, por defecto, se utiliza JSON. Además, TinyDB permite usar la memoria convencional como soporte de almacenamiento para las mismas.

Instalación con Pip


Para instalar TinyDB desde la consola:

En Linux:

$ sudo pip3 install tinydb

En Windows:

C:\> pip3 install tinydb

También, es posible descargar y descomprimir el archivo del módulo y después instalarlo con:

$ python3 setup.py install

 


Operaciones básicas con TinyDB


Para realizar los siguientes ejemplos recomendamos el entorno interactivo de Python u otro alternativo como IPython.

Importar módulos para realizar operaciones básicas


from tinydb import TinyDB, where

Abrir/Crear base de datos. Tabla por defecto ("_default")


cielo = TinyDB('cielo.db')

Abre la base de datos indicada o la crea si no existe. Cuando se crea una base de datos se agrega, automáticamente, una tabla llamada "_default". A continuación, si se insertan registros o se realizan otras operaciones propias de tablas se aplicarán a la misma.

Abrir/Crear una tabla con un nombre determinado


constelacion = cielo.table('constelacion')

Abre la tabla indicada o la crea si no existe en la base de datos. Después de abrir una base de datos si no se abre una tabla específica se abrirá la tabla "_default", quedando disponible para operar con ella.

Obtener los nombres de las tablas de una base de datos


tablas = cielo.tables()
tablas  #  {'_default', 'constelacion'}

Insertar registros en la tabla 'constelacion'


constelacion.insert({'nombre': 'Casiopea', 
                     'abrev': 'CAS', 
                     'sup': 598, 'obs': 
                     'Todo el año'})  # 1
constelacion.insert({'nombre': 'Cefeo', 
                     'abrev': 'CEP', 
                     'sup': 500, 'obs': 
                     'Todo el año'})  # 2

Cuando se añaden registros a una tabla, TinyDB les asigna un identificador (ID) numérico a cada registro.

Consultar todos los registros de la tabla 'constelacion'


registros = constelacion.all()
for registro in registros:
    print(registro['nombre'], 
          registro['abrev'], 
          registro['sup'], 
          registro['obs'])

Casiopea CAS 598 Todo el año
Cefeo CEP 500 Todo el año

Consultar todos los registros que cumplan una condición


registros = constelacion.search(where('obs') == 'Todo el año')
for registro in registros:
    print(registro['nombre'], 
          registro['abrev'], 
          registro['sup'], 
          registro['obs'])

Casiopea CAS 598 Todo el año
Cefeo CEP 500 Todo el año

La función search() devuelve una lista con los registros que cumplan la condición indicada. El primer registro encontrado se corresponderá con el elemento 0 de la lista, el segundo con el 1 y así, sucesivamente.

Consultar el primer registro que cumpla una condición


registros = constelacion.search(where('obs') == 'Todo el año')
print(registros[0]['nombre'], 
      registros[0]['abrev'], 
      registros[0]['sup'], 
      registros[0]['obs'])

Casiopea CAS 598 Todo el año

En el ejemplo se hace referencia al elemento 0 de la lista que se corresponde con el primer registro encontrado. Si no existen registros que cumplan la condición, al intentar visualizar se producirá una excepción del tipo IndexError que es necesario capturar:

try:
    registros = constelacion.search(where('obs') == 'Todo el mes')
    print(registros[0]['nombre'], 
          registros[0]['abrev'], 
          registros[0]['sup'], 
          registros[0]['obs'])

except IndexError:
    print("No existen registros")

No existen registros

Actualizar un dato de un registro que cumpla una condición


constelacion.update({'sup': 588}, where('nombre') == 'Cefeo')
constelacion.all()

[{'abrev': 'CAS', 'nombre': 'Casiopea', 'obs': 'Todo el año', 'sup': 598},
{'abrev': 'CEP', 'nombre': 'Cepeo', 'obs': 'Todo el año', 'sup': 588}]

En el registro de la constelación 'Cefeo' se actualiza el campo de la superficie 'sup' con el valor 588.

Suprimir los registros que cumplan una condición


constelacion.remove(where('sup') > 590)
constelacion.all()

[{'abrev': 'CEP', 'nombre': 'Cepeo', 'obs': 'Todo el año', 'sup': 588}]

En la tabla "constelacion" se borra el registro cuya superficie supera el valor de 590 grados cuadrados, es decir, en este caso el de la constelación 'Casiopea' que ocupa una superficie mayor, de 598 grados cuadrados.

Añadir un nuevo registro a la tabla 'constelacion'


constelacion.insert({'nombre': 'Dragón', 
                     'abrev': 'DRA', 
                     'sup': 1083, 
                     'obs': 'Todo el año'})  # 3

Mostrar el contenido del archivo de base de datos (cielo.db) desde la consola


En Linux:

$ cat cielo.db

En Windows:

c:\>type cielo.db


Contenido:

{"_default": {}, "constelacion": {"2": {"sup": 500, "obs": "Todo el a\u00f1o", "abrev": "CEP", "nombre": "Cepeo"}, "3": {"sup": 1083, "obs": "Todo el a\u00f1o", "abrev": "DRA", "nombre": "Drag\u00f3n"}}}

Como puede observarse el formato utilizado para almacenar los datos es totalmente abierto.

La base de datos del ejemplo es un diccionario con dos pares de claves/valor.

Las claves se corresponden con los nombres de las tablas disponibles: "_default" y "constelacion".

Los valores se corresponden con los datos de cada tabla. Éstos están organizados en una serie de diccionarios anidados (uno por cada registro). En el caso de la tabla "_default" las dos llaves {} indican que la tabla está vacía. Sin embargo, la tabla "constelación" contiene dos registros identificados con los ID "2" y "3" con sus campos/datos asociados contenidos igualmente en otro diccionario.

Borrar todos los registros de una tabla


constelacion.purge()

Borrar todas las tablas de la base de datos


cielo.purge_tables()

Cerrar una base de datos


cielo.close()


En el próximo capítulo: Uso avanzado de TinyDB


Ir al índice del tutorial de Python

viernes, 1 de mayo de 2015

Operaciones con archivos CSV


Un archivo CSV (de Valores Separados por Comas) es un tipo de documento que representa los datos de forma parecida a una tabla, es decir, organizando la información en filas y columnas.

En un archivo CSV los datos de las diferentes columnas son separados, habitualmente, por un signo de puntuación (una coma, un punto y coma, etc.) u otro carácter que actúe como separador. Sin embargo, las diferentes filas suelen separarse por un salto de línea. Además, muchas veces los datos pueden ir precedidos por un encabezado con los nombres de campos o identificadores de columnas:

nombre,provincia,consumo
Alejandro,Sevilla,330
Carmen,Sevilla,320
Eugenia,Granada,280
...

Un archivo CSV almacena la información en un formato accesible que facilita el intercambio entre aplicaciones. Es frecuente en muchos programas que utilizan datos de contactos contar con una opción para exportar la información en dicho formato. También, las aplicaciones ofimáticas de hojas de cálculos (Excel, Calc, etc.) incorporan opciones para guardar la información en CSV.

Asimismo, estos programas ofrecen la posibilidad de elegir el carácter delimitador de campos y, opcionalmente, el carácter que se utilizará como delimitador de textos o datos. Los delimitadores de textos o de datos, a veces, son necesarios para indicar dónde comienza y termina un dato, sobre todo si dentro de éste pueden aparecer en un momento dado caracteres iguales al usado como separador de campo.

En el ejemplo siguiente el delimitador de textos que se utiliza es la doble comilla. Su uso estaría justificado porque en el dato domicilio aparece el carácter coma y éste coincide justamente con el carácter empleado como delimitador de campos. Si la información la tuviera que leer un programa, gracias a la doble comilla, se podría analizar correctamente donde empiezan y terminan los distintos datos:

"Domicilio","Municipio"
"Cultura, 24","La Rinconada"
"Antonio Machado, 3","Sevilla"


Afortunadamente, el lenguaje Python tiene un módulo denominado csv que permite leer y escribir archivos en estos formatos; y provee, también, varias funciones y clases para verificar la integridad de la información, analizar o crear dialectos, comprobar si los datos tienen un encabezamiento, etc.

Los dialectos son los distintos formatos que se aplican a los archivos CSV. El dialecto excel es el que se utiliza de forma predeterminada y establece los campos separados por comas, generalmente. El dialecto excel-tab utiliza el tabulador como separador de campo y en el dialecto unix todos los datos se representan entrecomillados.

Por otro lado, ampliar la potencia del módulo csv es posible si conocemos algunas técnicas, por ejemplo, para filtrar la información y/o mostrarla ordenada; y mediante el uso de otras funciones.

A continuación, se muestran ejemplos que utilizan este módulo de la biblioteca estándar que hará las delicias de muchos. Para probar los ejemplos es necesario crear en un editor de textos los siguientes archivos CSV:

datos.csv
nombre,provincia,consumo
Alejandro,Sevilla,330
Carmen,Sevilla,320
Eugenia,Granada,280
Antonio,Sevilla,340
Ana,Granada,290
Marta,Granada,230
Luis,Huelva,310
Manuel,Huelva,340
Francisco,Granada,320

salidat.csv
campo1,campo2
aaa,111
bbb,222
ccc,333

También, hay que importar el módulo csv, protagonista de esta entrada, y el módulo operator que se utiliza en algún ejemplo:

import csv, operator

Leer archivo CSV con reader()


# Leer el archivo 'datos.csv' con reader() y 
# mostrar todos los registros, uno a uno:

with open('datos.csv') as csvarchivo:
    entrada = csv.reader(csvarchivo)
    for reg in entrada:
        print(reg)  # Cada línea se muestra como una lista de campos

Leer archivo CSV con reader() y realizar algunas operaciones básicas


# Leer el archivo 'datos.csv' con reader() y 
# realizar algunas operaciones básicas: 

csvarchivo = open('datos.csv')  # Abrir archivo csv
entrada = csv.reader(csvarchivo)  # Leer todos los registros
reg = next(entrada)  # Leer registro (lista)
print(reg)  # Mostrar registro
nombre, provincia, consumo = next(entrada)  # Leer campos
print(nombre, provincia, consumo)  # Mostrar campos
del nombre, provincia, consumo, entrada  # Borrar objetos
csvarchivo.close()  # Cerrar archivo
del csvarchivo  # Borrar objeto


Ordenar datos con sort(), sorted() e itemgetter()


La función sort() se utiliza para ordenar una lista en orden numérico, alfabético, etc.:

lista = ["d", "a", "e", "b", "c"]
lista.sort()
print(lista)  # ['a', 'b', 'c', 'd', 'e']

Por otro lado, disponemos de la función sorted() que permite utilizar otros criterios de ordenación, ampliando las posibilidades de sort():

sorted(objeto_a_ordenar, key=función, reverse=True|False)

La función sorted() devuelve un objeto con los elementos ordenados. Si se utiliza el argumento key se aplicará a cada elemento la función indicada. Para obtener los elementos ordenados con orden inverso hay que incluir el argumento reverse con el valor True. Ejemplos:

# Crear listas para ordenarlas con la función sorted()

lista1 = ['ABCDEF', 'ABCEFGHIJ', 'ABC', 'ABCD']
lista2 = ['10', '30', '20', '4']

# Ordenar lista1 por la longitud de sus elementos:

lista1 = sorted(lista1, key=len)
print('lista1 ordenada por longitud de cadenas: ', lista1)

# Ordenar lista1 por la longitud de sus elementos en orden inverso:

lista1 = sorted(lista1, key=len, reverse=True)
print('lista1 ordenada por longitud de cadenas inverso:', lista1)

# Ordenar lista2 por el valor numérico de sus elementos:

lista2 = sorted(lista2, key=int, reverse=False)
print('lista2 ordenada por valor numérico:', lista2)

Por otra parte, utilizar la función itemgetter() del módulo operator con la función sorted() permite ordenar una lista de tuplas (o de registros) por el índice de uno de sus campos (el índice del primer campo es el 0, del segundo el 1, etc.):

# Declarar una lista con cuatro tuplas de dos campos cada una:

lista = [('cccc', 4444), ('d', 1), ('aa', 22), ('bbb', 333)]

# Ordenar lista por el segundo campo de cada tupla (índice 1):

listaord = sorted(lista, key=operator.itemgetter(1), reverse=False)
print('lista ordenada por campo2:', listaord)

# Ordenar lista por primer campo de cada tupla (índice 0), 
# orden inverso:

listaord = sorted(lista, key=operator.itemgetter(0), reverse=True)
print('lista ordenada inversa por campo1:', listaord)

# Ordenar alfabéticamente por el primer campo:

listaord = sorted(lista)
print('lista ordenada alfabéticamente:', listaord)

Leer archivo CSV con reader() y ordenar salida por un campo


# Leer un archivo con reader() y mostrarlo ordenado por tercer
# campo con la función itemgetter() del módulo operator: 

csvarchivo = csv.reader(open('datos.csv'))
listaordenada = sorted(csvarchivo, 
                       key=operator.itemgetter(2), 
                       reverse=False)
print(listaordenada)


Leer archivo CSV con DictReader() y filtrar salida


# Leer un archivo csv como lista de diccionarios con DictReader() y
# mostrar sólo datos de algunas columnas:

with open('datos.csv') as csvarchivo:
    entrada = csv.DictReader(csvarchivo)
    for reg in entrada:
        print(reg['provincia'], reg['consumo'])


Leer archivo CSV con DictReader() y consultar propiedades


# Mostrar lista de diccionarios a partir CSV y 
# consultar número de líneas (registros), dialecto y campos:

csvarchivo = open('datos.csv')
entrada = csv.DictReader(csvarchivo)
listadicc = list(entrada)  # Obtener lista de diccionarios
print('Lista:', listadicc)  # Mostrar lista de diccionarios
print('Líneas:', entrada.line_num)  # Obtener número de registros
print('Dialecto:', entrada.dialect)  # Obtener dialecto
print('Campos:', entrada.fieldnames)  # Obtener nombre de campos
del entrada, listadicc
csvarchivo.close()
del csvarchivo


Leer archivo CSV con DictReader() y ordenar salida por nombre de campo


# Obtener lista ordenada descendente por el campo 'consumo' 
# con la función itemgetter() del módulo operator.

csvarchivo = open('datos.csv')
entrada = csv.DictReader(csvarchivo)
listadicc = list(entrada)  # Obtener lista de diccionarios
listadiccord = sorted(listadicc, 
                      key=operator.itemgetter('consumo'), 
                      reverse=True)
for registro in listadiccord:
    print(registro)

del entrada, listadicc, listadiccord
csvarchivo.close()
del csvarchivo


Escribir archivo CSV con writer() y writerow(). Quoting


La opción de quoting establece el tipo de entrecomillado que se aplicará a un archivo CSV. Existen cuatro posibilidades: QUOTE_ALL para entrecomillar todos los campos; QUOTE_MINIMAL para entrecomillar sólo los campos que sean necesarios para mantener la integridad de los datos; QUOTE_NONE para no entrecomillar nada y QUOTE_NONNUMERIC para entrecomillar sólo aquellos campos que no sean numéricos.


# Leer con DictReader y escribir datos en otro csv si se 
# cumple condición.
# En el archivo 'salida.csv' se escribirán todos los datos 
# entrecomillaods con dobles comillas y separados entre sí
# con el carácter "|".

with open('datos.csv') as csvarchivo:
    entrada = csv.DictReader(csvarchivo)
    csvsalida = open('salida.csv', 'w', newline='')
    salida = csv.writer(csvsalida, delimiter='|', 
                        quotechar='"', 
                        quoting=csv.QUOTE_ALL)
    print('Escribiendo archivo "salida.csv"...')
    print('Dialecto:', entrada.dialect, '...')
    for reg in entrada:
        if reg['provincia'] != 'Huelva':
            salida.writerow([reg['nom'], 
                             reg['cons']])  # Escribir registro
  
    print('El proceso de escritura ha terminado.')

del entrada, salida, reg
csvsalida.close()
del csvsalida


Escribir archivo CSV con writer() y writerows()


# Escribir todas las tuplas de una lista con writerows()

datos = [('aaa', 111), ('bbb', 222), ('ccc', 333)]
csvsalida = open('salidat.csv', 'w', newline='')
salida = csv.writer(csvsalida)
salida.writerow(['campo1', 'campo2'])
salida.writerows(datos)
del salida
csvsalida.close()


Leer archivo CSV con reader(), skipinitialspace y strict


# Leer archivo ignorando o no los espacios que existan después
# de los delimitadores de campos

# Si la propiedad skipinitialspace es True se ignorarán
# los espacios
# Si la propiedad strict es True se producirá un error si el 
# archivo csv no es válido 

# Leer archivos sin ignorar espacios

with open('archivo.csv') as csvarchivo:
    entrada = csv.reader(csvarchivo, 
                         skipinitialspace=False, 
                         strict=True)
    for reg in entrada:
        print(reg)

# Leer archivos ignorando espacios

with open('archivo.csv') as csvarchivo:
    entrada = csv.reader(csvarchivo, 
                         skipinitialspace=True, 
                         strict=True)
    for reg in entrada:
        print(reg)


Escribir archivo CSV con DictWriter() capturando excepciones


try:
    salidacsv = open('campos.csv', 'w')
    campos = ['Campo1', 'Campo2']
    salida = csv.DictWriter(salidacsv, fieldnames=campos)
    salida.writeheader()
    for indice in range(6):
        salida.writerow({ 'Campo1':indice+1,
                          'Campo2':chr(ord('a') + indice)})
 
    print('Se ha creado el archivo "campos.csv"')

finally:
    salidacsv.close()


Leer archivo CSV con reader() de un dialecto determinado


# Leer archivo csv con dialecto 'unix'

with open('salida.csv') as csvarchivo:
    entrada = csv.reader(csvarchivo, 
                         dialect='unix', 
                         delimiter='|')
    for reg in entrada:
        print(reg)


Crear dialecto y leer archivo CSV


# Crear nuevo dialecto 'personal' y abrir archivo usándolo.

csv.register_dialect('personal', 
                     delimiter='|', 
                     quotechar='"', 
                     quoting=csv.QUOTE_ALL)
with open('salida.csv') as csvarchivo:
    entrada = csv.reader(csvarchivo, dialect='personal')
    for reg in entrada:
        print(reg)


Listar dialectos disponibles


# Listar dialectos

print(csv.list_dialects())


Obtener información de un dialecto


# Obtener información del dialecto "personal"

dialecto = csv.get_dialect('personal')
print('delimiter', dialecto.delimiter)
print('skipinitialspace', dialecto.skipinitialspace)
print('doublequote', dialecto.doublequote)
print('quoting', dialecto.quoting)
print('quotechar', dialecto.quotechar)
print('lineterminator', dialecto.lineterminator)


Suprimir dialecto


# Suprimir dialecto "personal"

csv.unregister_dialect('personal')
print(csv.list_dialects())  # Listar dialectos después


Deducir con Sniffer() el dialecto de un archivo csv


with open('salida.csv') as csvarchivo:
    dialecto = csv.Sniffer().sniff(csvarchivo.read(48))
    csvarchivo.seek(0)
    print("Dialecto:", dialecto)
    csvarchivo.seek(0)
    entrada = csv.reader(csvarchivo, dialecto)
    for reg in entrada:
        print(reg)


Deducir con Sniffer() si un archivo tiene encabezado


# El archivo salida.csv no tiene encabezado

csvarchivo1 = open('salida.csv')
cabecera1 = csv.Sniffer().has_header(csvarchivo1.read(48))
print("\ncsvarchivo1 (salida.csv) cabecera:", cabecera1)
csvarchivo1.seek(0)
entrada = csv.reader(csvarchivo1, "unix")
for reg in entrada:
    print(reg)

csvarchivo1.close()

# El archivo salidat.csv sí tiene encabezado

csvarchivo2 = open('salidat.csv')
cabecera2 = csv.Sniffer().has_header(csvarchivo2.read(76))
print("\ncsvarchivo2 (salidat.csv) cabecera:", cabecera2)
csvarchivo2.seek(0)
entrada = csv.reader(csvarchivo2, "excel")
for reg in entrada:
    print(reg)

csvarchivo2.close()


Mostrar/Establecer límite de tamaño de campo a analizar


# Para establecer un nuevo límite: field_size_limit(NuevoLímite)

print(csv.field_size_limit())  



Ir al índice del tutorial de Python