web-dev-qa-db-fra.com

Mélanger des fichiers et des boucles

J'écris un script qui enregistre les erreurs d'un autre programme et le redémarre là où il s'était arrêté lorsqu'il rencontre une erreur. Pour une raison quelconque, les développeurs de ce programme n'ont pas jugé nécessaire d'intégrer cette fonctionnalité à leur programme par défaut.

Quoi qu'il en soit, le programme prend un fichier d'entrée, l'analyse et crée un fichier de sortie. Le fichier d'entrée est dans un format spécifique:

UI - 26474845
TI - the title (can be any number of lines)
AB - the abstract (can also be any number of lines)

Lorsque le programme génère une erreur, il vous fournit les informations de référence dont vous avez besoin pour suivre l'erreur, à savoir l'interface utilisateur, la section (titre ou résumé) et le numéro de ligne par rapport au début du titre ou de l'abrégé. Je souhaite consigner les phrases incriminées du fichier d'entrée avec une fonction qui prend le numéro de référence et le fichier, trouve la phrase et la consigne. La meilleure façon de le faire consiste à avancer dans le fichier un nombre de fois spécifique (à savoir, n fois, où n est le numéro de ligne par rapport au début de la section). La manière qui semblait logique de faire cela est la suivante:

i = 1
while i <= lineNumber:
    print original.readline()
    i += 1

Je ne vois pas en quoi cela me ferait perdre des données, mais Python pense que ce serait le cas et dit ValueError: Mixing iteration and read methods would lose data. Est-ce que quelqu'un sait comment faire cela correctement?

27
Allan Lavell

Vous obtenez ValueError car votre code a probablement for line in original: en plus de original.readline(). Une solution simple qui résout le problème sans ralentir votre programme ni utiliser plus de mémoire est en train de changer

for line in original:
    ...

à

while True:
    line = original.readline()
    if not line: break
    ...
49
pts

Utilisez for et enumerate .

Exemple:

for line_num, line in enumerate(file):
    if line_num < cut_off:
        print line

NOTE: Cela suppose que vous nettoyiez déjà vos descripteurs de fichiers, etc.

En outre, la fonction takewhile pourrait s'avérer utile si vous préférez une saveur plus fonctionnelle.

11
Hank Gay

En supposant que vous n’ayez besoin que d’une seule ligne, cela pourrait vous aider

import itertools

def getline(fobj, line_no):
    "Return a (1-based) line from a file object"
    return itertools.islice(fobj, line_no-1, line_no).next() # 1-based!

>>> print getline(open("/etc/passwd", "r"), 4)
'adm:x:3:4:adm:/var/adm:/bin/false\n'

Vous voudrez peut-être intercepter les erreurs StopIteration (si le fichier contient moins de lignes).

0
tzot

Voici une version sans le motif while True laid et sans autres modules:

for line in iter(original.readline, ''):
    if …:   # to the beginning of the title or abstract
        for i in range(lineNumber):
            print original.readline(),
        break
0
Armali