Зачем генерировать ValueError с помощью int () для чтения частей строк из файла .txt?

1

Это подпрограмма, которая читается из studentNamesfile.txt

def calculate_average():
'''Calculates and displays average mark.'''
test_results_file = open('studentNamesfile.txt', 'r')

total = 0
num_recs = 0
line = ' '
while line != '':
    line = test_results_file.readline()
    # Convert everything after the delimiting pipe character to an integer, and add it to total.
    total += int(line[line.find('|') + 1:])
    num_recs += 1
test_results_file.close()

[ num_recs содержит количество записей, считанных из файла.]

Формат studentNamesfile.txt выглядит следующим образом:

Student 01|10
Student 02|20
Student 03|30

и так далее. Эта подпрограмма предназначена для чтения метки всех записей студента в файле, но я получаю эту ошибку при ее запуске:

Traceback (most recent call last):
  File "python", line 65, in <module>
  File "python", line 42, in calculate_average
ValueError: invalid literal for int() with base 10: ''

Эта ошибка довольно ясна, но я не могу понять, почему ее бросают. Я пробовал отслеживать значение line[line.find('|') + 1:], но Python утверждает, что он имеет правильное значение (например, 10), когда я использую print(line[line.find('|') + 1:] на предыдущей строке. Что случилось?

Обновление: я рассматриваю возможность того, что line[line.find('|') + 1:] включает в себя новую line[line.find('|') + 1:] которая line[line.find('|') + 1:] int(). Но использование line[line.find('|') + 1:line.find('\\')] не устраняет проблему - возникает line[line.find('|') + 1:line.find('\\')] та же ошибка.

  • 0
    @Sharku еще не видел, дай мне взглянуть
  • 0
    @Sharku Я думаю, что мой вопрос немного отличается, хотя они похожи.
Показать ещё 1 комментарий
Теги:
file
python-3.x
type-conversion
file-handling

3 ответа

1
Лучший ответ

Вот:

while line != '':
    line = test_results_file.readline()

Когда вы попадаете в конец файла, .readline() возвращает пустую строку, но так как это происходит после .readline() while line != '', Вы все равно пытаетесь обработать эту строку.

Канонический (и гораздо более простой) способ перебора файла по строкам, который должен, ну, итерации по файлу, избежать этой проблемы:

for line in test_result_file:
    do_something_with(line)

Вам просто нужно позаботиться о вызове .rstrip() в line если вы хотите избавиться от символа окончания новой строки (что соответствует вашему коду).

Кроме того, вы хотите убедиться, что файл правильно закрыт, что происходит. Канонический способ - использовать open() в качестве менеджера контекста:

with open("path/to/file.txt") as f:
    for line in test_result_file:
        do_something_with(line)

Это вызовет f.close() при выходе из блока with, однако он f.close() только что закончен цикл for или произошло исключение).

Кроме того, вместо выполнения сложных вычислений, чтобы найти деталь после трубы, вы можете просто разделить строку:

for line in test_results_file:
    total = int(line.strip().split("|")[1])
     num_recs += 1

И, наконец, вы можете использовать модуль stdlib csv для анализа вашего файла вместо того, чтобы делать это вручную...

1

Потому что это не числовое значение. Таким образом, python бросает ValueError если он не способен преобразовать его в целое. Вы можете под кодом, чтобы проверить его.

def calculate_average():
  test_results_file = open('studentNamesfile.txt', 'r')
  total = 0
  num_recs = 0
  for line in test_results_file.readlines():
    try:
        total += int(line[line.find('|') + 1:])
        num_recs += 1
    except ValueError:
        print("Invalid Data: ", line[line.find('|') + 1:])
  test_results_file.close()
  print("total:", total)
  print("num_recs:", num_recs)
  print("Average:", float(total)/num_recs)

readlines vs readline

from io import StringIO
s = 'hello\n hi\n how are you\n'
f = StringIO(unicode(s))
l = f.readlines()
print(l)
# OUTPUT: [u'hello\n', u' hi\n', u' how are you\n']

f = StringIO(unicode(s)) 
l1 = f.readline()
# u'hello\n'
l2 = f.readline()
# u' hi\n'
l3 = f.readline()
# u' how are you\n'
l4 = f.readline()
# u''
l5 = f.readline()
# u''

readlines

Если мы используем readlines тогда он вернет список на основе символа \n.

Readline

Из кода выше видно, что у нас есть только 3 строки в stringIO но когда мы получаем доступ к readline он всегда дает нам пустую строку. поэтому в коде вы преобразуете его в целое число, потому что вы получаете исключение ValueError.

  • 0
    Когда я запускаю этот код, предложение except никогда не выполняется - оно работает! Вы изменили способ чтения файла?
  • 0
    @CRYasuo да. for line in test_results_file.readlines(): Пожалуйста, примите ответ и проголосуйте.
Показать ещё 2 комментария
0

Более простой подход.

Демо - версия:

total = 0
num_recs = 0

with open(filename) as infile:                            #Read File
    for line in infile:                                   #Iterate Each line
        if "|" in line:                                   #Check if | in line
            total += int(line.strip().split("|")[-1])     #Extract value and sum
            num_recs += 1
print(total, num_recs)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню