@nohchiborz

Почему вложенный цикл теряет доступ к открытому файлу со второй итерации основного цикла?

Допустим, есть код:
a = open("A.txt")
b = open("B.txt")
finish_all = open("finish.txt","w")

for a_line in a:
    for b_line in b:
        if a_line != b_line:
            finish_all.write(a_line)

когда я его запускаю, то вложенный цикл проходит по элементам в файле лишь один раз. Например, в файле "А" 10 элементов, а в "B" - 5, то в этом случае вложенный цикл по элементам файла "B" пройдет лишь один раз, в то время, как основной цикл продолжит работу. Будто вложенный цикл после первой итерации теряет из виду файл, по которому должен пройтись.
Но! Если повторить строчку открытия файла в теле основного цикла, то вложенный цикл вдруг срабатывает до конца. В чем же дело?
Кстати, на всякий случай, этот код не реализует того, чего я хотел от него, а именно запись в finish.txt элементов из A.txt, предварительно удалив оттуда лишнее по шаблону из файла B.txt. Но я справлюсь с этим после того как пойму, что не так с вложенным циклом)
Спасибо заранее.
  • Вопрос задан
  • 283 просмотра
Решения вопроса 1
@deliro
Потому что это вложенные циклы, а не параллельные.
Если тебе нужно удалить из А все элементы, которые есть в B, при этом, длины файлов недостаточно большие, чтобы занять всю твою оперативку, можно сделать так:
with open('A.txt') as a, open('B.txt') as b, open('finish.txt', 'w') as finish:
    a_items = [l.strip() for l in a]
    b_set = {l.strip() for l in b}
    finish.write('\n'.join(item for item in a_items if item not in b_set))


Если в finish.txt не важно, не будет дубликатов из А или нет (или, например, A.txt содержит только уникальные значения) и порядок не важен тоже:
with open('A.txt') as a, open('B.txt') as b, open('finish.txt', 'w') as finish:
    a_set = {l.strip() for l in a}
    b_set = {l.strip() for l in b}
    finish.write('\n'.join(a_set - b_set))
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
@fireSparrow
Итерация по файлу отличается от итерации по списку.
При использовании в цикле списка, готового объекта-итератора нет, и для списка интерпретатор создаёт объект-итератор.
Но файловый объект - сам себе итератор, поэтому интерпретатор использует для итерирования уже существующий итератор, а не создаёт новый. Поэтому, если итератор файлового объекта исчерпается после прохода по нему, то к следующему витку он так и останется исчерпанным.
Ответ написан
@abcd0x00
Используй b.seek(0) после каждого цикла по b. И не забудь закрыть файлы после работы с ними - хороший стиль. Либо используй with изначально.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы