Как правильно зациклить два файла параллельно в Python - PullRequest
9 голосов
/ 02 декабря 2009

Я часто пишу код вроде:

lines = open('wordprob.txt','r').readlines()
words = open('StdWord.txt','r').readlines()
i = 0
for line in lines:
    v = [eval(s) for s in line.split()]
    if v[0] > v[1]:
        print words[i].strip(),
    i += 1

Можно ли избежать использования переменной i и сделать программу короче?

Спасибо.

Ответы [ 4 ]

21 голосов
/ 02 декабря 2009

Похоже, вам все равно, какое значение i. Вы просто используете его как способ объединения lines и words. Поэтому я рекомендую вам читать по одной строке за раз и одновременно читать по одному слову. Тогда они будут совпадать.

Кроме того, когда вы используете .readlines(), вы одновременно читаете все данные в памяти. Для больших входов это будет медленно. Для этого простого кода по одной строке все, что вам нужно. Файловый объект, возвращаемый open(), может действовать как итератор, который возвращает по одной строке за раз.

Если вы можете, вы должны избегать использования eval(). В простом упражнении, где вы знаете, какими будут входные данные, это довольно безопасно, но если вы получаете данные из внешних источников, использование eval() может позволить вашему компьютеру быть атакованным. См. эту страницу для получения дополнительной информации. Я напишу свой пример кода, чтобы предположить, что вы используете eval() для преобразования текста в значение float. float() также будет работать с целочисленным строковым значением: float('3') вернет 3.0.

Также представляется, что входные строки могут иметь только два значения. Если строка когда-либо имеет дополнительные значения, ваш код не обнаружит это условие. Мы можем изменить код, чтобы явно распаковать два значения из строки разделения, а затем, если существует более двух значений, Python вызовет исключение. Кроме того, код будет немного приятнее для чтения.

Итак, вот мое рекомендуемое переписывание этого примера:

lines = open('wordprob.txt','rt')
words = open('StdWord.txt','rt')

for line in lines:
    word = words.next().strip()  # in Python 3: word = next(words).strip()
    a, b = [float(s) for s in line.split()]
    if a > b:
        print word,  # in Python 3: print(word + ' ', end='')

РЕДАКТИРОВАТЬ: И здесь то же решение, но с использованием izip().

import itertools
lines = open('wordprob.txt','rt')
words = open('StdWord.txt','rt')

# in Python 3, just use zip() instead of izip()
for line, word in itertools.izip(lines, words):
    word = word.strip()
    a, b = [float(s) for s in line.split()]
    if a > b:
        print word,  # in Python 3: print(word + ' ', end='')

В Python 3 встроенный zip() возвращает итератор, так что вы можете просто использовать его без необходимости import itertools.

EDIT: Рекомендуется использовать оператор with, чтобы убедиться, что файлы правильно закрыты, несмотря ни на что. В последних версиях Python вы можете иметь несколько операторов with, и я сделаю это в своем решении. Кроме того, мы можем распаковать выражение генератора так же легко, как распаковать список, поэтому я изменил строку, которая устанавливает a, b, чтобы использовать выражение генератора; это должно быть немного быстрее. И нам не нужно раздевать word, если мы не собираемся его использовать. Положите изменения вместе, чтобы получить:

from itertools import izip

with open('wordprob.txt','rt') as lines, open('StdWord.txt','rt') as words:
    # in Python 3, just use zip() instead of izip()
    for line, word in izip(lines, words):
        a, b = (float(s) for s in line.split())
        if a > b:
            print word.strip(),  # in Python 3: print(word.strip() + ' ', end='')
15 голосов
/ 02 декабря 2009

Вы можете попробовать использовать enumerate,

http://docs.python.org/tutorial/datastructures.html#looping-techniques

lines = open('wordprob.txt','r').readlines()
words = open('StdWord.txt','r').readlines()
for i,line in enumerate(lines):
        v = [eval(s) for s in line.split()]
        if v[0] > v[1]:
                print words[i].strip()
5 голосов
/ 02 декабря 2009

В целом перечисление является хорошим решением. В этом случае вы можете сделать что-то вроде:

lines = open('wordprob.txt','r').readlines()
words = open('StdWord.txt','r').readlines()
for word, line in zip(words, lines):
    v = [eval(s) for s in line.split()]
    if v[0] > v[1]:
            print word.strip(),
1 голос
/ 02 декабря 2009

Взгляните на перечислить :

>>> for i, season in enumerate(['Spring', 'Summer', 'Fall', 'Winter']):
...     print i, season
0 Spring
1 Summer
2 Fall
3 Winter
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...