-1

I have a grade.txt which consist of

Mickey,Mouse,90*
Jane,Doe,50
Minnie,Mouse,95
Donald,Duck,80
Daffy,Duck,70

Trying to read the file and split to separate the names and grades while calculating the average. I'm receiving line not defined.

def main ():
  with open('grade.txt' , 'r') as f:
    lines = f.readlines(); #reads all the line in file to lines list.

  f.close(); #closes f stream.

sum = 0; #initialised sum to store the sum of all grades.

print('Name    Grade');

print('--------------------');

for line in lines: #loops through the lines list

  str = line.split(','); #splits each line based on ','

  grade = int(str[2]); #converts string to numeric value.

  sum += grade; #adds the grade value to sum.

  print(str[0]," ",str[1]," ",grade); #prints the line read after splitting.

print('Average Grade: ',round((sum/len(lines)),1)); #prints average of all grades by rounding it to 1 place.

newdata = input('Enter firstname,lastname and grade: '); #prompts user.

with open('grade.txt', 'a') as f: #opens file in append mode.

  f.write('\n'+newdata); #writes data into file in new line.

f.close(); #closes f stream
main ()

assistance in the right direction appreciated.

The error gave

 Traceback (most recent call last):
 File "main.py", line 13, in <module>
 for line in lines: #loops through the lines list
 NameError: name 'lines' is not defined

edited code

def main ():
  with open('grades.txt' , 'r') as f:
    lines = f.readlines(); #reads all the line in file to lines list.

  sum = 0; #initialised sum to store the sum of all grades.

  print('Name    Grade');

  print('--------------------');

  for line in lines: #loops through the lines list

    str = line.split(','); #splits each line based on ','

    grade = int(str[2]); #converts string to numeric value.

    sum += grade; #adds the grade value to sum.

    print(str[0]," ",str[1]," ",grade); #prints the line read after splitting.

  print('Average Grade: ',round((sum/len(lines)),1)); #prints average of all grades by rounding it to 1 place.

newdata = input('Enter firstname,lastname and grade: '); #prompts user.

with open('grades.txt', 'a') as f: #opens file in append mode.

  f.write('\n'+newdata); #writes data into file in new line.

f.close(); #closes f stream

Thanks, I got passed the line error with indentions and removed the f.close; passing that I see my code isn't outputting the contents of the file. It's only printing newdata

DoRebel
  • 1
  • 2
  • You don't have to close the file when using `with`. – Axel Puig Dec 06 '18 at 00:30
  • It looks like your indentation is broken. [Indentation matters in Python.](https://stackoverflow.com/questions/45621722/im-getting-an-indentationerror-how-do-i-fix-it) – user2357112 Dec 06 '18 at 00:31
  • (And yes, I know the error isn't an IndentationError. That doesn't mean it's not caused by indentation problems.) – user2357112 Dec 06 '18 at 00:31
  • What error are you getting? I see you mention "line not defined" but it's not clear what that means.. Can you paste the whole error trace? – tomas Dec 06 '18 at 00:32

2 Answers2

1

When you create a variable like lines, it can only be used in the function it is created in.

Your main function actually ends after the line f.close();. To make everything a part of your main function, you need to keep the same level of indentation.

def main ():
  with open('grade.txt' , 'r') as f:
    lines = f.readlines(); #reads all the line in file to lines list.

  f.close(); #closes f stream.

  sum = 0; #initialised sum to store the sum of all grades.

  print('Name    Grade');

  print('--------------------');

  for line in lines: #loops through the lines list

    str = line.split(','); #splits each line based on ','

    grade = int(str[2]); #converts string to numeric value.

    sum += grade; #adds the grade value to sum.

    print(str[0]," ",str[1]," ",grade); #prints the line read after splitting.

  print('Average Grade: ',round((sum/len(lines)),1)); #prints average of all grades by rounding it to 1 place.

  newdata = input('Enter firstname,lastname and grade: '); #prompts user.

  with open('grade.txt', 'a') as f: #opens file in append mode.

    f.write('\n'+newdata); #writes data into file in new line.

  f.close(); #closes f stream
main ()

A couple of pointers with your code. In Python semicolons are not required at the end of each line.

And the line f.close() is unnecessary when using a with block. The file is automatically closed at the end of the with block.

hostingutilities.com
  • 8,894
  • 3
  • 41
  • 51
0

It has to do with variable scope.

with open('grade.txt', 'r') as f:
    lines = f.readlines()

lines is defined WITHIN the with statement and therefore no longer exists when the with statement exits (file is closed).

Based on your indention, and therefore variable scope, it matters where you "use" lines.

with open('grade.txt', 'r') as f:
    lines = f.readlines()

    # "lines" is visible here.
    do_something_here()

# "lines" is not defined here.
for line in lines:
    wont_work()

However, your code will work if you define lines outside the with statement. This changes the scope of "lines" and causes it to persist throughout the with statement, although this is arguably sloppier code. For example:

lines = []
with open('grade.txt', 'r') as f:
    lines = f.readlines()

# lines persists and now contains the content of the file. So you can still operate on it.
do_something_here()

Simple solution:

def main():
    print("Name               Grade")
    print('-------------------------')

    with open('grade.txt', 'r') as file:
        sum = 0
        count = 0

        for line in file:
            # Strip the line of all white space and new lines "\n" usually found in text files.
            # Also strip the "*" found in the original input file.
            # Split content based on ",".
            entry = line.strip().strip("*").split(',')

            # Extract name and grade.
            name = entry[0] + " " + entry[1]
            grade = entry[2]

            print("{:<20}{:>2}".format(name, grade))

            sum += int(grade)
            count += 1

        print("Average Grade:      {:.1f}".format(sum / count))


if __name__ == '__main__':
    main()

Notes about Python:

  1. You don't need semicolons ;.
  2. Try to use 4 spaces for indention. Use [PEP 8 (https://www.python.org/dev/peps/pep-0008/) guidelines.
  3. You don't need to use file.close() when using "with". The file is closed automatically. Search how with statements work in Python: http://effbot.org/zone/python-with-statement.htm
  4. If your text file is HUUUUUUUGE, doing file.readlines() loads it all into memory at once. If you ever run into problems iterate over each line in the file one at a time:
with open('grade.txt', 'r') as file:
    for line in file:
        # efficient memory usage
        do_something
print(type(file))

output:

<class '_io.TextIOWrapper'>