Запуск питона через входной файл
Мой вопрос связан с вводом файлов в Python, используя open()
. У меня есть текстовый файл mytext.txt
с 3 строками.
Я пытаюсь сделать две вещи с этим файлом: напечатать строки и напечатать количество строк.
Я попробовал следующий код:
input_file = open('mytext.txt', 'r')
count_lines = 0
for line in input_file:
print line
for line in input_file:
count_lines += 1
print 'number of lines:', count_lines
Результат: он правильно печатает 3 строки, но печатает "количество строк: 0" (вместо 3)
Я нашел два способа его решения и распечатал 3
:
1) Я использую один цикл вместо двух
input_file = open('mytext.txt', 'r')
count_lines = 0
for line in input_file:
print line
count_lines += 1
print 'number of lines:', count_lines
2) после первого цикла, я снова определяю input_file
input_file = open('mytext.txt', 'r')
count_lines = 0
for line in input_file:
print line
input_file = open('mytext.txt', 'r')
for line in input_file:
count_lines += 1
print 'number of lines:', count_lines
Мне кажется, что определение input_file = ...
допустимо только для одного цикла, как если бы он был удален после использования его для цикла. Но я не понимаю, почему, возможно, мне это пока еще не ясно, как variable = open(filename)
обрабатывается в Python.
Кстати, я вижу, что в этом случае лучше использовать только один цикл. Тем не менее, я чувствую, что мне нужно понять этот вопрос, поскольку могут быть случаи, когда я могу/должен его использовать.
Ответы
Ответ 1
Дескриптор файла - это итератор. После итерации по файлу указатель будет помещен в EOF (конец файла), и итератор будет вызывать StopIteration, который выходит из цикла. Если вы попытаетесь использовать итератор для файла, в котором указатель находится в EOF, он просто поднимет StopIteration и выйдет: вот почему во втором цикле он равен нулю. Вы можете перематывать указатель файла с помощью input_file.seek(0)
без его повторного открытия.
Тем не менее, подсчет строк в одном и том же цикле является более эффективным вводом-выводом, иначе вам придется читать весь файл с диска во второй раз, только чтобы подсчитать строки. Это очень распространенная картина:
with open('filename.ext') as input_file:
for i, line in enumerate(input_file):
print line,
print "{0} line(s) printed".format(i+1)
В Python 2.5 файловый объект был оснащен __enter__
и __exit__
, чтобы обратиться к with
statement interface. Это синтаксический сахар для чего-то вроде:
input_file = open('filename.txt')
try:
for i, line in enumerate(input_file):
print line,
finally:
input_file.close()
print "{0} line(s) printed".format(i+1)
Я думаю, что cPython закроет дескрипторы файлов, когда они получат сбор мусора, но я не уверен, что это верно для каждой реализации - IMHO лучше практиковать явно закрывать дескрипторы ресурсов.
Ответ 2
Есть ли причина, по которой вы не можете использовать следующее:
input_file = open('mytext.txt', 'r')
count_lines = 0
for line in input_file:
print line
count_lines += 1
print 'number of lines:', count_lines
Вещь, возвращаемая open, является файловым объектом. Файловые объекты отслеживают свое внутреннее положение, когда вы их зацикливаете, поэтому для того, чтобы сделать то, что вы пробовали в первую очередь, вам придется перемотать его в начало вручную, он не сделает этого сам по себе.
Ответ 3
Попробуйте добавить input_file.seek(0)
между двумя циклами. Это перемотает файл назад в начало, так что вы можете снова перебрать его.
Ответ 4
Я удаляю файл fileinput модуля.
Вот ссылка
if __name__ == "__main__":
for line in fileinput.input():
if fileinput.isfirstline():
print("current file: %s" % fileinput.filename())
print("line number: %d, current file number: %d" %
(fileinput.lineno(), fileinput.filelineno()))