Comment lire un gros fichier - ligne par ligne?


536

Je veux parcourir chaque ligne d'un fichier entier. Une façon de procéder consiste à lire l'intégralité du fichier, à l'enregistrer dans une liste, puis à parcourir la ligne d'intérêt. Cette méthode utilise beaucoup de mémoire, donc je cherche une alternative.

Mon code jusqu'à présent:

for each_line in fileinput.input(input_file):
    do_something(each_line)

    for each_line_again in fileinput.input(input_file):
        do_something(each_line_again)

L' exécution de ce code donne un message d'erreur: device active.

Aucune suggestion?

Le but est de calculer la similitude des chaînes par paire, ce qui signifie que pour chaque ligne du fichier, je veux calculer la distance Levenshtein avec toutes les autres lignes.


4
Pourquoi avez-vous besoin de relire le fichier entier pour chaque ligne? Peut-être que si vous dites ce que vous essayez d'accomplir, quelqu'un pourrait suggérer une meilleure approche.
JJJ

Réponses:


1269

La façon correcte et entièrement Pythonique de lire un fichier est la suivante:

with open(...) as f:
    for line in f:
        # Do something with 'line'

L' withinstruction gère l'ouverture et la fermeture du fichier, y compris si une exception est déclenchée dans le bloc interne. Le for line in ftraite l'objet fichier fcomme un itérable, qui utilise automatiquement les E / S tamponnées et la gestion de la mémoire pour que vous n'ayez pas à vous soucier des gros fichiers.

Il devrait y avoir une - et de préférence une seule - manière évidente de le faire.


14
oui, c'est la meilleure version avec python 2.6 et supérieur
Simon Bergot

3
Personnellement, je préfère les générateurs et les coroutines pour traiter les pipelines de données.
jldupont

4
quelle serait la meilleure stratégie si un fichier est un énorme fichier texte mais avec une seule ligne et l'idée est de traiter les mots?
mfcabrera

4
Quelqu'un pourrait-il expliquer comment ça for line in f:marche? Je veux dire, comment itérer sur un objet fichier est-il possible?
haccks

11
Si vous parcourez un objet, Python recherche dans la liste des méthodes objet une méthode spéciale appelée __iter__, qui lui indique quoi faire. Les objets fichier définissent cette méthode spéciale pour renvoyer un itérateur sur les lignes. (En gros.)
Katriel

130

Deux moyens efficaces de mémoire dans l'ordre classé (le premier est le meilleur) -

  1. utilisation de with- pris en charge à partir de python 2.5 et supérieur
  2. utilisation de yieldsi vous voulez vraiment contrôler la quantité de lecture

1. utilisation de with

withest le moyen pythonique agréable et efficace de lire de gros fichiers. avantages - 1) l'objet fichier est automatiquement fermé après avoir quitté le withbloc d'exécution. 2) gestion des exceptions à l'intérieur du withbloc. 3) la forboucle de mémoire parcourt le ffichier objet ligne par ligne. en interne, il fait des E / S tamponnées (optimisées pour les opérations d'E / S coûteuses) et la gestion de la mémoire.

with open("x.txt") as f:
    for line in f:
        do something with data

2. utilisation de yield

Parfois, on peut souhaiter un contrôle plus fin sur la quantité à lire à chaque itération. Dans ce cas, utilisez iter & yield . Notez qu'avec cette méthode, il faut explicitement fermer le fichier à la fin.

def readInChunks(fileObj, chunkSize=2048):
    """
    Lazy function to read a file piece by piece.
    Default chunk size: 2kB.
    """
    while True:
        data = fileObj.read(chunkSize)
        if not data:
            break
        yield data

f = open('bigFile')
for chuck in readInChunks(f):
    do_something(chunk)
f.close()

Pièges et par souci d'exhaustivité - les méthodes ci-dessous ne sont pas aussi bonnes ou pas aussi élégantes pour lire des fichiers volumineux, mais veuillez lire pour obtenir une compréhension globale.

En Python, la façon la plus courante de lire les lignes d'un fichier est de procéder comme suit:

for line in open('myfile','r').readlines():
    do_something(line)

Lorsque cela est fait, cependant, la readlines()fonction (il en va de même pour la read()fonction) charge tout le fichier en mémoire, puis itère dessus. Une approche légèrement meilleure (les deux premières méthodes mentionnées sont les meilleures) pour les fichiers volumineux consiste à utiliser le fileinputmodule, comme suit:

import fileinput

for line in fileinput.input(['myfile']):
    do_something(line)

l' fileinput.input()appel lit les lignes de façon séquentielle, mais ne les garde pas en mémoire après qu'elles ont été lues ou même simplement ceci, car fileen python est itérable.

Références

  1. Python avec instruction

9
-1 Ce n'est fondamentalement jamais une bonne idée à faire for line in open(...).readlines(): <do stuff>. Pourquoi voudrais-tu?! Vous venez de perdre tous les avantages de l'intelligent IO de l'itérateur tamponné de Python sans aucun avantage.
Katriel

5
@Srikar: il y a un temps et un lieu pour donner toutes les solutions possibles à un problème; enseigner à un débutant comment faire la saisie de fichiers n'est-ce pas. Avoir la bonne réponse enfouie au bas d'un long post plein de mauvaises réponses n'est pas un bon enseignement.
Katriel

6
@Srikar: Vous pouvez améliorer considérablement votre publication en mettant le bon chemin en haut, puis en mentionnant readlineset en expliquant pourquoi ce n'est pas une bonne chose à faire (car il lit le fichier en mémoire), puis en expliquant ce que fait le fileinputmodule et pourquoi vous pourrait vouloir l'utiliser par-dessus les autres méthodes, expliquant ensuite comment la segmentation du fichier améliore l'IO et donnant un exemple de la fonction de segmentation (mais en mentionnant que Python le fait déjà pour vous, vous n'avez donc pas besoin de le faire). Mais donner cinq façons de résoudre un problème simple, dont quatre sont erronées dans ce cas, n'est pas bon.
Katriel

2
Tout ce que vous ajoutez par souci d'exhaustivité, ajoutez-le en dernier, pas en premier. Montrez d'abord la bonne façon.
m000

6
@katrielalex a revu ma réponse et a constaté qu'elle justifiait une restructuration. Je peux voir comment la réponse précédente pourrait créer de la confusion. J'espère que cela clarifiera les choses pour les futurs utilisateurs.
Srikar Appalaraju

37

Pour supprimer les retours à la ligne:

with open(file_path, 'rU') as f:
    for line_terminated in f:
        line = line_terminated.rstrip('\n')
        ...

Avec le soutien de saut de ligne universel toutes les lignes de fichiers texte sembleront terminé avec '\n', quelles que soient les terminateurs dans le fichier, '\r', '\n'ou '\r\n'.

EDIT - Pour spécifier la prise en charge universelle de la nouvelle ligne:

  • Python 2 sur Unix - open(file_path, mode='rU')- requis [merci @Dave ]
  • Python 2 sur Windows - open(file_path, mode='rU')- facultatif
  • Python 3 - open(file_path, newline=None)- facultatif

Le newlineparamètre est uniquement pris en charge dans Python 3 et par défaut à None. Le modeparamètre par défaut est 'r'dans tous les cas. Le Uest dépréciée en Python 3. En Python 2 sous Windows un autre mécanisme semble traduire \r\nà \n.

Documents:

Pour conserver les terminateurs de ligne natifs:

with open(file_path, 'rb') as f:
    with line_native_terminated in f:
        ...

Le mode binaire peut toujours analyser le fichier en lignes avec in. Chaque ligne aura les terminateurs qu'elle contient dans le fichier.

Merci à @katrielalex de » réponse , Python open () doc, et ipython expériences.


1
Sur Python 2.7, je devais open(file_path, 'rU')activer les sauts de ligne universels.
Dave

17

c'est une façon possible de lire un fichier en python:

f = open(input_file)
for line in f:
    do_stuff(line)
f.close()

il n'alloue pas de liste complète. Il parcourt les lignes.


2
Bien que cela fonctionne, ce n'est certainement pas la voie canonique. La manière canonique est d'utiliser un wrapper de contexte, comme with open(input_file) as f:. Cela vous permet d'économiser f.close()et de vous assurer de ne pas oublier accidentellement de le fermer. Empêche les fuites de mémoire et tout, assez important lors de la lecture des fichiers.
Mast

1
Comme l'a dit @Mast, ce n'est pas la voie canonique, alors votez pour cela.
azuax

12

Un peu de contexte pour savoir d'où je viens. Les extraits de code sont à la fin.

Lorsque je le peux, je préfère utiliser un outil open source comme H2O pour effectuer des lectures de fichiers CSV parallèles de très haute performance, mais cet outil est limité dans l'ensemble de fonctionnalités. Je finis par écrire beaucoup de code pour créer des pipelines de science des données avant d'alimenter le cluster H2O pour l'apprentissage supervisé proprement dit.

J'ai lu des fichiers comme un ensemble de données HIGGS de 8 Go à partir du référentiel UCI et même des fichiers CSV de 40 Go à des fins de science des données beaucoup plus rapidement en ajoutant beaucoup de parallélisme avec l'objet pool et la fonction de carte de la bibliothèque de multitraitement. Par exemple, le clustering avec les recherches de voisins les plus proches et les algorithmes de clustering DBSCAN et Markov nécessitent une finesse de programmation parallèle pour contourner certains problèmes de mémoire et d'horloge murale très difficiles.

J'aime généralement diviser le fichier en plusieurs parties en utilisant d'abord les outils gnu, puis les masquer tous pour les trouver et les lire en parallèle dans le programme python. J'utilise couramment quelque chose comme plus de 1000 fichiers partiels. Faire ces astuces aide énormément avec la vitesse de traitement et les limites de mémoire.

Le fichier pandas dataframe.read_csv est un thread unique, vous pouvez donc faire ces astuces pour accélérer les pandas en exécutant une carte () pour une exécution parallèle. Vous pouvez utiliser htop pour voir qu'avec de vieux pandas séquentiels dataframe.read_csv, 100% de processeur sur un seul cœur est le véritable goulot d'étranglement dans pd.read_csv, pas le disque du tout.

Je dois ajouter que j'utilise un SSD sur un bus de carte vidéo rapide, pas un HD tournant sur le bus SATA6, plus 16 cœurs de processeur.

En outre, une autre technique que j'ai découverte fonctionne très bien dans certaines applications: le fichier CSV parallèle lit tout dans un fichier géant, en démarrant chaque travailleur à un décalage différent dans le fichier, plutôt que de pré-fractionner un gros fichier en plusieurs fichiers de pièce. Utilisez la recherche de fichier () et tell () de python dans chaque travailleur parallèle pour lire le gros fichier texte en bandes, à différents emplacements de début et de fin de décalage d'octet dans le gros fichier, le tout en même temps. Vous pouvez effectuer une recherche regex sur les octets et renvoyer le nombre de sauts de ligne. Il s'agit d'une somme partielle. Enfin, additionnez les sommes partielles pour obtenir la somme globale lorsque la fonction de carte revient une fois que les travailleurs ont terminé.

Voici quelques exemples de références utilisant l'astuce de décalage d'octets parallèles:

J'utilise 2 fichiers: HIGGS.csv fait 8 Go. Il provient du référentiel d'apprentissage automatique UCI. all_bin .csv fait 40,4 Go et provient de mon projet actuel. J'utilise 2 programmes: le programme GNU wc fourni avec Linux et le programme pur python fastread.py que j'ai développé.

HP-Z820:/mnt/fastssd/fast_file_reader$ ls -l /mnt/fastssd/nzv/HIGGS.csv
-rw-rw-r-- 1 8035497980 Jan 24 16:00 /mnt/fastssd/nzv/HIGGS.csv

HP-Z820:/mnt/fastssd$ ls -l all_bin.csv
-rw-rw-r-- 1 40412077758 Feb  2 09:00 all_bin.csv

ga@ga-HP-Z820:/mnt/fastssd$ time python fastread.py --fileName="all_bin.csv" --numProcesses=32 --balanceFactor=2
2367496

real    0m8.920s
user    1m30.056s
sys 2m38.744s

In [1]: 40412077758. / 8.92
Out[1]: 4530501990.807175

C'est quelque 4,5 Go / s, ou 45 Go / s, la vitesse de slurping des fichiers. Ce n'est pas un disque dur qui tourne, mon ami. C'est en fait un SSD Samsung Pro 950.

Ci-dessous se trouve la référence de vitesse pour le même fichier compté par gnu wc, un programme compilé en C pur.

Ce qui est cool, c'est que vous pouvez voir que mon programme en python pur correspondait essentiellement à la vitesse du programme C compilé par gnu wc dans ce cas. Python est interprété mais C est compilé, c'est donc un exploit de vitesse assez intéressant, je pense que vous serez d'accord. Bien sûr, wc doit vraiment être changé en un programme parallèle, et alors il devrait vraiment battre les chaussettes de mon programme python. Mais tel qu'il est aujourd'hui, gnu wc n'est qu'un programme séquentiel. Vous faites ce que vous pouvez, et python peut faire du parallèle aujourd'hui. La compilation de Cython pourrait m'aider (pour une autre fois). Les fichiers mappés en mémoire n'ont pas encore été explorés.

HP-Z820:/mnt/fastssd$ time wc -l all_bin.csv
2367496 all_bin.csv

real    0m8.807s
user    0m1.168s
sys 0m7.636s


HP-Z820:/mnt/fastssd/fast_file_reader$ time python fastread.py --fileName="HIGGS.csv" --numProcesses=16 --balanceFactor=2
11000000

real    0m2.257s
user    0m12.088s
sys 0m20.512s

HP-Z820:/mnt/fastssd/fast_file_reader$ time wc -l HIGGS.csv
11000000 HIGGS.csv

real    0m1.820s
user    0m0.364s
sys 0m1.456s

Conclusion: La vitesse est bonne pour un programme en python pur par rapport à un programme C. Cependant, il n'est pas suffisant d'utiliser le programme python pur sur le programme C, au moins à des fins de comptage de lignes. Généralement, la technique peut être utilisée pour d'autres traitements de fichiers, donc ce code python est toujours bon.

Question: Est-ce que la compilation de l'expression régulière une seule fois et sa transmission à tous les employés améliorera la vitesse? Réponse: La pré-compilation Regex n'aide PAS dans cette application. Je suppose que la raison en est que les frais généraux de sérialisation et de création de processus pour tous les travailleurs sont dominants.

Encore une chose. La lecture de fichiers CSV parallèle aide-t-elle même? Le disque est-il le goulot d'étranglement ou est-ce le CPU? De nombreuses réponses dites les mieux notées sur stackoverflow contiennent la sagesse courante des développeurs selon laquelle vous n'avez besoin que d'un seul thread pour lire un fichier, le mieux que vous puissiez faire, disent-ils. Mais sont-ils sûrs?

Découvrons-le:

HP-Z820:/mnt/fastssd/fast_file_reader$ time python fastread.py --fileName="HIGGS.csv" --numProcesses=16 --balanceFactor=2
11000000

real    0m2.256s
user    0m10.696s
sys 0m19.952s

HP-Z820:/mnt/fastssd/fast_file_reader$ time python fastread.py --fileName="HIGGS.csv" --numProcesses=1 --balanceFactor=1
11000000

real    0m17.380s
user    0m11.124s
sys 0m6.272s

Oh oui, oui. La lecture de fichiers en parallèle fonctionne plutôt bien. Et bien voilà!

Ps. Dans le cas où certains d'entre vous voudraient savoir, que se passe-t-il si le balanceFactor était de 2 lors de l'utilisation d'un seul processus de travail? Eh bien, c'est horrible:

HP-Z820:/mnt/fastssd/fast_file_reader$ time python fastread.py --fileName="HIGGS.csv" --numProcesses=1 --balanceFactor=2
11000000

real    1m37.077s
user    0m12.432s
sys 1m24.700s

Parties clés du programme python fastread.py:

fileBytes = stat(fileName).st_size  # Read quickly from OS how many bytes are in a text file
startByte, endByte = PartitionDataToWorkers(workers=numProcesses, items=fileBytes, balanceFactor=balanceFactor)
p = Pool(numProcesses)
partialSum = p.starmap(ReadFileSegment, zip(startByte, endByte, repeat(fileName))) # startByte is already a list. fileName is made into a same-length list of duplicates values.
globalSum = sum(partialSum)
print(globalSum)


def ReadFileSegment(startByte, endByte, fileName, searchChar='\n'):  # counts number of searchChar appearing in the byte range
    with open(fileName, 'r') as f:
        f.seek(startByte-1)  # seek is initially at byte 0 and then moves forward the specified amount, so seek(5) points at the 6th byte.
        bytes = f.read(endByte - startByte + 1)
        cnt = len(re.findall(searchChar, bytes)) # findall with implicit compiling runs just as fast here as re.compile once + re.finditer many times.
    return cnt

Le def pour PartitionDataToWorkers est juste du code séquentiel ordinaire. Je l'ai laissé de côté au cas où quelqu'un d'autre voudrait se familiariser avec la programmation parallèle. J'ai donné gratuitement les parties les plus difficiles: le code parallèle testé et fonctionnel, pour votre bénéfice d'apprentissage.

Merci à: Le projet open source H2O, par Arno et Cliff et le personnel H2O pour leurs excellents logiciels et vidéos pédagogiques, qui m'ont inspiré ce lecteur de décalage d'octets parallèle en python pur de haute performance comme indiqué ci-dessus. H2O fait la lecture de fichiers en parallèle en utilisant java, est appelable par les programmes python et R, et est incroyablement rapide, plus rapide que n'importe quoi sur la planète pour lire de gros fichiers CSV.


Les morceaux parallèles sont ce que c'est, fondamentalement. De plus, je m'attends à ce que SSD et Flash soient les seuls périphériques de stockage compatibles avec cette technique. Il est peu probable que Spinning HD soit compatible.
Geoffrey Anderson

1
Comment avez-vous pris en compte les fichiers du disque de mise en cache du système d'exploitation?
JamesThomasMoon1979

5

Katrielalex a fourni le moyen d'ouvrir et de lire un fichier.

Cependant, la façon dont votre algorithme fonctionne, il lit le fichier entier pour chaque ligne du fichier. Cela signifie que la quantité globale de lecture d'un fichier - et de calcul de la distance Levenshtein - sera effectuée N * N si N est la quantité de lignes dans le fichier. Étant donné que vous êtes préoccupé par la taille du fichier et que vous ne souhaitez pas le conserver en mémoire, je suis préoccupé par le temps d'exécution quadratique résultant . Votre algorithme est dans la classe d'algorithmes O (n ^ 2) qui peut souvent être améliorée avec la spécialisation.

Je soupçonne que vous connaissez déjà le compromis entre la mémoire et l'exécution ici, mais vous voudrez peut-être rechercher s'il existe un moyen efficace de calculer plusieurs distances Levenshtein en parallèle. Si c'est le cas, il serait intéressant de partager votre solution ici.

Combien de lignes vos fichiers ont-ils, et sur quel type de machine (puissance mem & cpu) votre algorithme doit-il fonctionner, et quel est le temps d'exécution toléré?

Le code ressemblerait à:

with f_outer as open(input_file, 'r'):
    for line_outer in f_outer:
        with f_inner as open(input_file, 'r'):
            for line_inner in f_inner:
                compute_distance(line_outer, line_inner)

Mais les questions sont de savoir comment stocker les distances (matrice?) Et pouvez-vous gagner un avantage à préparer, par exemple, la ligne extérieure pour le traitement, ou à mettre en cache certains résultats intermédiaires pour la réutilisation.


Mon point est que ce post ne contient pas de réponse à la question, juste quelques autres questions! OMI, il serait mieux adapté en tant que commentaire.
Katriel

1
@katriealex: Euh. Étrange. Vous avez vu les boucles imbriquées, développant votre propre réponse pour l'adapter à la question réelle? Je peux retirer mes questions ici de ma réponse, et il y a encore suffisamment de contenu pour justifier de fournir cette réponse - bien que partielle -. Je pourrais également accepter si vous modifiez votre propre réponse pour inclure l'exemple de boucle imbriquée - qui a été explicitement demandé par la question - et je peux ensuite supprimer ma propre réponse avec bonheur. Mais un downvote est quelque chose que je ne reçois pas du tout.
cfi

C'est suffisant; Je ne vois pas vraiment de démonstration des boucles imbriquées comme réponse à la question, mais je suppose que c'est plutôt fortement destiné aux débutants. Downvote supprimé.
Katriel

3
#Using a text file for the example
with open("yourFile.txt","r") as f:
    text = f.readlines()
for line in text:
    print line
  • Ouvrez votre fichier pour lecture (r)
  • Lisez l'intégralité du fichier et enregistrez chaque ligne dans une liste (texte)
  • Parcourez la liste en imprimant chaque ligne.

Si vous voulez, par exemple, vérifier une ligne spécifique pour une longueur supérieure à 10, travaillez avec ce que vous avez déjà disponible.

for line in text:
    if len(line) > 10:
        print line

1
Pas mieux pour cette question, mais ce code est principalement utile dans le cas où ce que vous recherchez.est "slurping" (lecture du fichier entier à la fois). C'était mon cas et Google m'a amené ici. +1. En outre, pour l'atomicité, ou si vous faites du temps, le traitement dans la boucle peut se terminer plus rapidement pour lire le fichier entier
ntg

1
En outre, le code a été amélioré un peu: 1. la fermeture n'est pas nécessaire après avec: ( docs.python.org/2/tutorial/inputoutput.html , recherchez "Il est recommandé d'utiliser le mot clé with ...") 2 . Le texte peut être traité après la lecture du fichier (en dehors de la boucle ....)
ntg

2

Dans la documentation python pour fileinput .input ():

Cela parcourt les lignes de tous les fichiers répertoriés dans sys.argv[1:], par défaut sys.stdinsi la liste est vide

de plus, la définition de la fonction est:

fileinput.FileInput([files[, inplace[, backup[, mode[, openhook]]]]])

lire entre les lignes, cela me dit que cela filespeut être une liste afin que vous puissiez avoir quelque chose comme:

for each_line in fileinput.input([input_file, input_file]):
  do_something(each_line)

Voir ici pour plus d'informations


2

Je recommande fortement de ne pas utiliser le chargement de fichier par défaut car il est horriblement lent. Vous devriez regarder dans les fonctions numpy et les fonctions IOpro (par exemple numpy.loadtxt ()).

http://docs.scipy.org/doc/numpy/user/basics.io.genfromtxt.html

https://store.continuum.io/cshop/iopro/

Ensuite, vous pouvez diviser votre opération par paire en morceaux:

import numpy as np
import math

lines_total = n    
similarity = np.zeros(n,n)
lines_per_chunk = m
n_chunks = math.ceil(float(n)/m)
for i in xrange(n_chunks):
    for j in xrange(n_chunks):
        chunk_i = (function of your choice to read lines i*lines_per_chunk to (i+1)*lines_per_chunk)
        chunk_j = (function of your choice to read lines j*lines_per_chunk to (j+1)*lines_per_chunk)
        similarity[i*lines_per_chunk:(i+1)*lines_per_chunk,
                   j*lines_per_chunk:(j+1)*lines_per_chunk] = fast_operation(chunk_i, chunk_j) 

Il est presque toujours beaucoup plus rapide de charger des données en morceaux et de faire ensuite des opérations matricielles dessus que de le faire élément par élément !!


0

Besoin de lire fréquemment un gros fichier à partir de la dernière lecture de position?

J'ai créé un script utilisé pour couper un fichier Apache access.log plusieurs fois par jour. J'ai donc dû placer un curseur de position sur la dernière ligne analysée lors de la dernière exécution . À cette fin, j'ai utilisé file.seek()et des file.seek()méthodes qui permettent le stockage du curseur dans un fichier.

Mon code:

ENCODING = "utf8"
CURRENT_FILE_DIR = os.path.dirname(os.path.abspath(__file__))

# This file is used to store the last cursor position
cursor_position = os.path.join(CURRENT_FILE_DIR, "access_cursor_position.log")

# Log file with new lines
log_file_to_cut = os.path.join(CURRENT_FILE_DIR, "access.log")
cut_file = os.path.join(CURRENT_FILE_DIR, "cut_access", "cut.log")

# Set in from_line 
from_position = 0
try:
    with open(cursor_position, "r", encoding=ENCODING) as f:
        from_position = int(f.read())
except Exception as e:
    pass

# We read log_file_to_cut to put new lines in cut_file
with open(log_file_to_cut, "r", encoding=ENCODING) as f:
    with open(cut_file, "w", encoding=ENCODING) as fw:
        # We set cursor to the last position used (during last run of script)
        f.seek(from_position)
        for line in f:
            fw.write("%s" % (line))

    # We save the last position of cursor for next usage
    with open(cursor_position, "w", encoding=ENCODING) as fw:
        fw.write(str(f.tell()))

-2

La meilleure façon de lire un fichier volumineux, ligne par ligne, est d'utiliser la fonction d' énumération python

with open(file_name, "rU") as read_file:
    for i, row in enumerate(read_file, 1):
        #do something
        #i in line of that line
        #row containts all data of that line

3
Pourquoi utiliser énumérer mieux? Le seul avantage par rapport à la réponse acceptée est que vous obtenez un index dont OP n'a pas besoin et que vous rendez le code moins lisible.
fuyas
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.