Leer un archivo línea por línea en Python

    Introducción

    A lo largo de mi vida laboral he tenido la oportunidad de utilizar muchos conceptos y tecnologías de programación para hacer innumerables cosas. Algunas de estas cosas involucran frutos de mi trabajo de valor relativamente bajo, como la automatización de lo propenso a errores o mundano como la generación de informes, la automatización de tareas y el reformateo de datos generales. Otros han sido mucho más valiosos, como el desarrollo de productos de datos, aplicaciones web y canalizaciones de análisis y procesamiento de datos. Una cosa que es notable acerca de casi todos estos proyectos es la necesidad de simplemente abrir un archivo, analizar su contenido y hacer algo con él.

    Sin embargo, ¿qué hace cuando el archivo que está intentando consumir es bastante grande? ¿Qué pasa si el archivo tiene varios GB de datos o más? Una vez más, este ha sido otro aspecto frecuente de mi carrera de programación, que se ha pasado principalmente en el sector de BioTech, donde es común encontrar archivos de más de 1 TB de tamaño.

    La respuesta a este problema es leer fragmentos de un archivo a la vez, procesarlo y luego liberarlo de la memoria para poder extraer y procesar otro fragmento hasta que se haya procesado todo el archivo masivo. Si bien depende del programador determinar un tamaño de fragmento adecuado, para muchas aplicaciones es adecuado procesar un archivo una línea a la vez.

    A lo largo de este artículo, cubriremos una serie de ejemplos de código para mostrar cómo leer archivos línea por línea. En caso de que desee probar algunos de estos ejemplos usted mismo, el código utilizado en este artículo se puede encontrar en el siguiente Repositorio de GitHub.

    E / S de archivo básico en Python

    Al ser un gran lenguaje de programación de propósito general, Python tiene una serie de funciones de E / S de archivos muy útiles en su biblioteca estándar de funciones y módulos integrados. El incorporado open() función es lo que se utiliza para abrir una objeto de archivo ya sea para leer o escribir.

    fp = open('path/to/file.txt', 'r')
    

    los open() La función toma múltiples argumentos. Nos centraremos en los dos primeros, siendo el primero un parámetro de cadena posicional que representa la ruta al archivo que se debe abrir. El segundo parámetro opcional también es una cadena, que especifica el modo de interacción que desea para el objeto de archivo que devuelve la llamada a la función. Los modos más comunes se enumeran en la tabla siguiente, siendo el valor predeterminado ‘r’ para lectura.

    Descripción del modo

    rAbierto para leer texto sin formato
    wAbierto para escribir texto sin formato
    aAbra un archivo existente para agregar texto sin formato
    rbAbierto para leer datos binarios
    wbAbierto para escribir datos binarios

    Una vez que haya escrito o leído todos los datos deseados para un objeto de archivo, debe cerrar el archivo para que los recursos puedan reasignarse en el sistema operativo en el que se ejecuta el código.

    fp.close()
    

    A menudo verá muchos fragmentos de código en Internet o en programas en la naturaleza que no cierran explícitamente los objetos de archivo que se han generado de acuerdo con el ejemplo anterior. Siempre es una buena práctica cerrar un recurso de objeto de archivo, pero muchos de nosotros somos demasiado perezosos u olvidadizos para hacerlo o pensamos que somos inteligentes porque la documentación sugiere que un objeto de archivo abierto se cerrará automáticamente una vez que finalice un proceso. Este no es siempre el caso.

    En lugar de insistir en lo importante que es llamar siempre close() en un objeto de archivo, me gustaría proporcionar una forma alternativa y más elegante de abrir un objeto de archivo y asegurarme de que el intérprete de Python se limpie después de nosotros 🙂

    with open('path/to/file.txt') as fp:
        # do stuff with fp
    

    Simplemente usando el with palabra clave (introducida en Python 2.5) para envolver nuestro código para abrir un objeto de archivo, las partes internas de Python harán algo similar al siguiente código para asegurarse de que no importa qué objeto de archivo se cierre después de su uso.

    try:
        fp = open('path/to/file.txt')
    
        # do stuff with fp
    finally:
        fp.close()
    

    Cualquiera de estos dos métodos es adecuado, siendo el primer ejemplo la forma más “Pythonic”.

    Leer línea por línea

    Ahora, vayamos a leer un archivo. El objeto de archivo devuelto por open() tiene tres métodos explícitos comunes (read, readliney readlines) para leer datos y una forma más implícita.

    los read El método leerá todos los datos en una cadena de texto. Esto es útil para archivos más pequeños en los que le gustaría realizar una manipulación de texto en todo el archivo o en cualquier otra cosa que le convenga. Entonces hay readline que es una forma útil de leer solo cantidades incrementales de línea individual a la vez y devolverlas como cadenas. El último método explícito, readlines, leerá todas las líneas de un archivo y las devolverá como una lista de cadenas.

    Como se mencionó anteriormente, puede usar estos métodos para cargar solo pequeñas partes del archivo a la vez. Para hacer esto con estos métodos, puede pasarles un parámetro que indique cuántos bytes cargar a la vez. Este es el único argumento que aceptan estos métodos.

    A continuación se muestra una implementación para leer un archivo de texto una línea a la vez, que se realiza a través del readline() método.

    Nota: Durante el resto de este artículo, demostraré cómo leer en el texto del libro La “Ilíada de Homero”, que se puede encontrar en gutenberg.org, así como en el repositorio de GitHub donde está el código para este artículo.

    En readline.py encontrará el siguiente código. En la terminal si corres $ python readline.py puedes ver el resultado de leer todas las líneas de la Ilíada, así como sus números de línea.

    filepath="Iliad.txt"
    with open(filepath) as fp:
       line = fp.readline()
       cnt = 1
       while line:
           print("Line {}: {}".format(cnt, line.strip()))
           line = fp.readline()
           cnt += 1
    

    El fragmento de código anterior abre un objeto de archivo almacenado como una variable llamada fp, luego lee en una línea a la vez llamando readline en ese objeto de archivo iterativamente en un while loop y lo imprime en la consola.

    Al ejecutar este código, debería ver algo como lo siguiente:

    $ python forlinein.py 
    Line 0: BOOK I
    Line 1: 
    Line 2: The quarrel between Agamemnon and Achilles--Achilles withdraws
    Line 3: from the war, and sends his mother Thetis to ask Jove to help
    Line 4: the Trojans--Scene between Jove and Juno on Olympus.
    Line 5: 
    Line 6: Sing, O goddess, the anger of Achilles son of Peleus, that brought
    Line 7: countless ills upon the Achaeans. Many a brave soul did it send
    Line 8: hurrying down to Hades, and many a hero did it yield a prey to dogs and
    Line 9: vultures, for so were the counsels of Jove fulfilled from the day on
    ...
    

    Si bien esto está perfectamente bien, hay una forma final que mencioné brevemente antes, que es menos explícita pero un poco más elegante, que prefiero mucho. Esta forma final de leer un archivo línea por línea incluye iterar sobre un objeto de archivo en un for bucle, asignando cada línea a una variable especial llamada line. El fragmento de código anterior se puede replicar en el siguiente código, que se puede encontrar en el script de Python forlinein.py:

    filepath="Iliad.txt"
    with open(filepath) as fp:
       for cnt, line in enumerate(fp):
           print("Line {}: {}".format(cnt, line))
    

    En esta implementación, estamos aprovechando una funcionalidad de Python incorporada que nos permite iterar sobre el objeto de archivo implícitamente usando un for bucle en combinación con el uso del objeto iterable fp. Esto no solo es más fácil de leer, sino que también se necesitan menos líneas de código para escribir, lo que siempre es una buena práctica que vale la pena seguir.

    Una aplicación de ejemplo

    Sería negligente escribir una aplicación sobre cómo consumir información en un archivo de texto sin demostrar al menos un uso trivial de cómo usar una habilidad tan valiosa. Dicho esto, estaré demostrando una pequeña aplicación que se puede encontrar en wordcount.py, que calcula la frecuencia de cada palabra presente en “La Ilíada de Homero” usada en ejemplos anteriores. Esto crea una simple bolsa de palabras, que se usa comúnmente en aplicaciones de PNL.

    import sys
    import os
    
    def main():
       filepath = sys.argv[1]
    
       if not os.path.isfile(filepath):
           print("File path {} does not exist. Exiting...".format(filepath))
           sys.exit()
      
       bag_of_words = {}
       with open(filepath) as fp:
           cnt = 0
           for line in fp:
               print("line {} contents {}".format(cnt, line))
               record_word_cnt(line.strip().split(' '), bag_of_words)
               cnt += 1
       sorted_words = order_bag_of_words(bag_of_words, desc=True)
       print("Most frequent 10 words {}".format(sorted_words[:10]))
      
    def order_bag_of_words(bag_of_words, desc=False):
       words = [(word, cnt) for word, cnt in bag_of_words.items()]
       return sorted(words, key=lambda x: x[1], reverse=desc)
    
    def record_word_cnt(words, bag_of_words):
        for word in words:
            if word != '':
                if word.lower() in bag_of_words:
                    bag_of_words[word.lower()] += 1
                else:
                    bag_of_words[word.lower()] = 1
    
    if __name__ == '__main__':
        main()
    

    El código anterior representa una secuencia de comandos de Python de línea de comando que espera una ruta de archivo pasada como argumento. El script usa el os module para asegurarse de que la ruta del archivo pasada sea un archivo que existe en el disco. Si la ruta existe, cada línea del archivo se lee y se pasa a una función llamada record_word_cnt como una lista de cadenas, delimitó los espacios entre palabras, así como un diccionario llamado bag_of_words. los record_word_cnt La función cuenta cada instancia de cada palabra y la registra en la bag_of_words diccionario.

    Una vez leídas y registradas todas las líneas del archivo en el bag_of_words diccionario, luego una llamada de función final a order_bag_of_words se llama, que devuelve una lista de tuplas en formato (palabras, recuento de palabras), ordenadas por recuento de palabras. La lista de tuplas devuelta se utiliza para imprimir las 10 palabras que aparecen con más frecuencia.

    Conclusión

    Entonces, en este artículo hemos explorado formas de leer un archivo de texto línea por línea de dos formas, incluida una forma que creo que es un poco más Pythonic (esta es la segunda forma demostrada en forlinein.py). Para resumir, presenté una aplicación trivial que es potencialmente útil para leer y preprocesar datos que podrían usarse para análisis de texto o análisis de sentimientos.

    Como siempre, espero sus comentarios y espero que puedan utilizar lo que se ha discutido para desarrollar aplicaciones interesantes y útiles.

    Etiquetas:

    Deja una respuesta

    Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *