簡體   English   中英

在 Python3 中編輯 csv 文件

[英]Editing a csv file in Python3

您好,我對使用 python 編輯 csv 文件有點陌生。 我正在做一個項目。 這是一個簡單的成績計算器,它讀取名為 new_grade.csv 的 csv 文件。 我的腳本計算每個學生的平均成績。 我不小心硬編碼了我的腳本,並且在讀取多個 csv 行時遇到了問題。 我的問題是如何修改我的代碼以運行任意一行數據。 我的代碼只對第一行數據起作用。 任何幫助將不勝感激。

我的 .csv 文件:

Smithy, James, 100, 78, 92, 92, 85, 85, 95, 100, 75, 85, 50, 85, 87, 95, 95, 80, 80, 96, 95, 95, 95, 85, 79, 95, 85, 95, A, A+, A, B, A+, F, C, B, A, A, A, A, 85, 95, 82, 91
Gadget, John, 0, 0, 92, 92, 85, 60, 85, 100, 75, 85, 50, 85, 0, 95, 85, 70, 70, 0, 95, 95, 95, 85, 0, 95, 0, 95, F, F, F, B, A+, A, C, B, C, F, F, F, 45, 75, 82, 31
Phillips, David, 100, 78, 92, 92, 85, 90, 85, 100, 75, 85, 50, 85, 87, 95, 85, 80, 80, 96, 95, 95, 95, 85, 79, 95, 85, 95, A, A+, A, B, A+, A, A, B, C, A, A, A, 85, 95, 82, 91 

我可以解決一行數據的代碼:

def main():
    try:
        import csv
        import sys
        # This section opens up the file grades.csv. It will then read the data and then takes that data and converts
        # that data into a list. When it's in a list we can splice the data to compute averages.
        with open("new_grade.csv", 'r') as f:
            list(csv.reader(f))  # had data = variable

        while True:
            # function to remove \n character from csv file
            def remove_newlines(fname):
                flist = open(fname).readlines()
                return [s.rstrip('\n') for s in flist]

            old_line = (remove_newlines("new_grade.csv"))
            # For required output:
            line = old_line[0].split(', ')  # This open up the line of the file. For instance this opens up line 1 of
            # file.
            if len(line) > 44:  # This checks to make sure that the data doesn't exceed 44 indexes
                print('The data in your file exceeds the maximum amount. Check line 1 of your file. ')
                sys.exit(1)

            def student():
                print((line[0]) + ',' + ' ' + (line[1]), end=', ')  # This finds the student's name

            def preparation_assignment_average():  # This will compute the preparation assignment average.
                global prep
                prep = 0
                for i in (line[2:16]):
                    i = int(i)
                    if 0 <= i <= 100:  # This is checking to make sure that the grades are in the range 0-100
                        prep = prep + int(i)
                    else:  # if it is not in the range of 0-100 it will print this statement and end the program
                        print('One of the values that you entered is not valid. Please enter a grade within the '
                              'range 0-100, Error\noccurred on line 1 in text file.')
                        sys.exit(1)  # This ends the program if it fails the if statement
                print(round((prep / 14), 2), end=', ')

            def lab_score_average():  # This will compute the lab score average
                global lab
                lab = 0
                for i in (line[17:28]):
                    i = int(i)
                    if 0 <= i <= 100:  # This is checking to make sure that the grades are in the range 0-100
                        lab = lab + int(i)
                    else:  # if it is not in the range of 0-100 it will print this statement and end the program
                        print('One of the values that you entered is not valid. Please enter a grade within the '
                              'range 0-100, Error\noccurred on line 1 in text file.')
                        sys.exit(1)  # This ends the program if it fails the if statement
                print(round((lab / 12), 2), end=', ')

            def post_lab_average():  # This calculates the post lab average of the student. It takes a letter and
                # converts the letter to a score that is an integer.
                global score
                score = 0
                for i in (line[28:39]):
                    if i == "A+":
                        score += 100
                    elif i == "A":
                        score += 95
                    elif i == "A-":
                        score += 90
                    elif i == "B":
                        score += 85
                    elif i == "C":
                        score += 75
                    elif i == "D":
                        score += 60
                    elif i == "F":
                        score += 0
                    elif i is not "A+" or "A" or "A-" or "B" or "C" or "D" or "F":
                        print('Your file is not formatted to the standard of the program. On line 1 of your file, '
                              'you have\na score where a letter grade should be. Please check file and rerun the '
                              'program.')
                        sys.exit(1)
                print(round((score / 12), 2), end=', ')

            def exam_average():  # This will compute the exam average for the student
                global exam
                exam = 0
                for i in (line[40:44]):
                    i = int(i)
                    if 0 <= i <= 100:  # This is checking to make sure that the grades are in the range 0-100
                        exam = exam + int(i)
                    else:  # if it is not in the range of 0-100 it will print this statement and end the program
                        print('One of the values that you entered is not valid. Please enter a grade within the '
                              'range 0-100, Error\noccurred on line 1 in text file.')
                        sys.exit(1)  # This ends the program if it fails the if statement
                print(round((exam / 4), 2), end=', ')

            def overall_weighted_class_average():  # This will compute the overall class average for the student
                global weighted_class_grade
                global weighted_prep
                global weighted_lab
                global weighted_score
                global weighted_exam
                weighted_prep = ((prep / 14) * .10)  # This is calculating the weighted average for a
                weighted_lab = ((lab / 12) * .20)  # This is calculating the weighted average for b
                weighted_score = ((score / 12) * .10)  # This is calculating the weighted average for score
                weighted_exam = ((exam / 4) * .60)  # This is calculating the weighted average for exam
                weighted_class_grade = round((weighted_prep + weighted_lab + weighted_score + weighted_exam), 2)
                print(weighted_class_grade, end=', ')

            def letter_grade_for_class():  # This will take the weighted class grade and it will print that grade
                # according to the range
                letter = weighted_class_grade
                while True:
                    if 95 < letter <= 100:
                        print("A+")
                        break
                    elif letter == 95:
                        print("A")
                        break
                    elif 90 <= letter <= 94:
                        print("A-")
                        break
                    elif 85 < letter <= 89:
                        print("B+")
                        break
                    elif letter == 85:
                        print("B")
                        break
                    elif 80 <= letter <= 84:
                        print("B-")
                        break
                    elif 75 < letter <= 79:
                        print("C+")
                        break
                    elif letter == 75:
                        print("C")
                        break
                    elif 70 <= letter <= 74:
                        print("C-")
                        break
                    elif 65 < letter <= 69:
                        print("D+")
                        break
                    elif letter == 65:
                        print("D")
                        break
                    elif 60 <= letter <= 64:
                        print("D-")
                        break
                    elif letter <= 59:
                        print("F")
                        break

            def call_functions():  # This takes all the definitions and makes it into one definition
                student()
                preparation_assignment_average()
                lab_score_average()
                post_lab_average()
                exam_average()
                overall_weighted_class_average()
                letter_grade_for_class()
                return ''

            break
        # After computing all the averages for the line of data it then writes it to a new file
        original_stdout = sys.stdout
        file = open('test_file.csv', 'x')  # The x will not save the file if it already exists
        sys.stdout = file
        for i in call_functions():
            file.writelines('\n%s' % i)
            sys.stdout = original_stdout
            file.close()
        f.close()
        
      except ValueError:  # displays when one of the letters is out of its index
        print('Sorry, one of the letters in the file is out of place. Please check the file again to make sure that \n'
              'the letter is not where the numbers are supposed to be. Check indexes 29-39. That is where the \n'
              'letter grades for the file should be.')
        sys.exit(1)
    except FileNotFoundError:  # displays error if there is no file by that name
        print("Sorry, the current file that you have selected is not a File.")
        sys.exit(1)
    except IndexError:  # this displays when there is no data in the file
        print('The file that you have selected does not contain any grades. Please check the file again.')
        sys.exit(1)
    except PermissionError:
        print('The file that you are trying to save is already a file. The file is protected and can not be written.')
        sys.exit(1)
    except FileExistsError:
        print('The file that you are trying to save is already a file. Please rename your file or delete that file '
              'and rerun the program.')
        sys.exit(1)
if __name__ == "__main__":
    main()

我認為有兩件事可以解釋您所看到的行為並暗示您可以修改代碼的方式。

  1. line = old_line[0].split(', ')表示您只讀取文件的第一行。 你應該有某種循環訪問文件的每一行line = old_line[index].split(',')

  2. 以下循環可能不會執行您認為的操作:

for i in call_functions():
    file.writelines('\n%s' % i)
    sys.stdout = original_stdout
    file.close()

call_functions()方法實際上返回一個空字符串,所以這個循環的主體實際上根本不運行。 call_functions()只被調用一次,這就是你在輸出 csv 中只看到一行輸出的原因。 您需要為 CSV 中的每一行調用call_functions()

這是一篇冗長的文章,因此我將其分成幾部分以使其更具可讀性。 完整代碼位於更改說明的末尾。

第一部分

我復制並粘貼了您的代碼,PyCharm 和 Visual Studio 在第 72 行為您的post_lab_average()函數捕獲了 SyntaxWarning 錯誤。

這是觸發它的elif語句:

elif i is not "A+" or "A" or "A-" or "B" or "C" or "D" or "F":

該程序只是希望您更改is not !=但老實說,您在這里不需要表達式,因為您已經要檢查所有其他字母。 你只需要一個else:而不是elif i != 'A+' or 'A' or ...

在進行我將要解釋的所有其他更改之后,程序再次在本節中遇到問題if i == "A+":如果它檢查的行中有多余的空間,則無法工作,即i = " A+" . 為了解決這個問題,我們將表達式改寫為if "A+" in i:這允許我們檢查"A+"無論是否有額外的空格。

你的post_lab_average()應該是這樣的:

def post_lab_average():

    global score
    score = 0
    for i in (line[28:39]):
        if "A+" in i:
            score += 100
        elif "A" in i:
            score += 95
        elif "A-" in i:
            score += 90
        elif "B" in i:
            score += 85
        elif "C" in i:
            score += 75
        elif "D" in i:
            score += 60
        elif "F" in i:
            score += 0
        else:
            print('Your file is not formatted to the standard of the program. On line 1 of your file, '
                  'you have\na score where a letter grade should be. Please check file and rerun the '
                  'program.')
            exit(1)

此外,在整個代碼中,您調用sys.exit(1)來終止程序sys.exit(1) sys. 是不必要的,只使用exit(1)就可以了。

第二部分

彈出的下一個錯誤是該行的異常FileExistsError

file = open('test_file.csv', 'x')

最后,我們會將數據附加到 csv 文件,因此我們將在main()函數的開頭包含這行代碼:

import os

try:
    os.remove('test_file.csv')
except FileNotFoundError:
    pass

如果文件存在,這將始終刪除該文件,並且您可以在最后刪除您的except FileExistsError:因為異常將不再觸發。

第三部分

使用with open()打開文件時,默認設置是讀取文件,因此您不需要添加'r'您實際上不需要函數remove_newlines() ,我們將打開文件並分配數據到像這樣的列表:

with open('new_grade.csv') as file:
    student_list = list(csv.reader(file))

第四部分

現在我們將調整您的while True循環以使用計數器運行,當它運行完所有列表時停止。

count = 0
while count < len(student_list):
    line = student_list[count]
    count += 1

循環將繼續,直到遍歷student_list所有子列表。 您必須在循環結束時擺脫break才能使其正常工作。

第五部分

快完成了! 在當前狀態下運行文件將生成一個文件,其中只有最后一個學生的條目。 為了解決這個問題,我們將縮進寫入文件的代碼塊,以便它在每個循環結束時運行,而不是在循環結束后運行。 我還重新格式化以with open('a')一起使用with open('a')這樣我們就可以附加我們的數據而不是覆蓋。

original_stdout = sys.stdout
with open('test_file.csv', 'a') as file:
    sys.stdout = file
    for i in call_functions():
        file.writelines('\n%s' % i)
        sys.stdout = original_stdout

最終代碼

def main():
    try:
        import csv
        import sys
        import os

        # Checks if file exists and removes it if found
        try:
            os.remove('test_file.csv')
        except FileNotFoundError:
            pass

        # Opens the data file and assigns it to a list
        with open('new_grade.csv') as file:
            student_list = list(csv.reader(file))

        # Loops through each student in list
        count = 0
        while count < len(student_list):
            line = student_list[count]
            count += 1

            if len(line) > 44:  # This checks to make sure that the data doesn't exceed 44 indexes
                print('The data in your file exceeds the maximum amount. Check line 1 of your file. ')
                sys.exit(1)

            def student():
                print((line[0]) + ',' + ' ' + (line[1]), end=', ')  # This finds the student's name

            def preparation_assignment_average():  # This will compute the preparation assignment average.
                global prep
                prep = 0
                for i in (line[2:16]):
                    i = int(i)
                    if 0 <= i <= 100:  # This is checking to make sure that the grades are in the range 0-100
                        prep = prep + int(i)
                    else:  # if it is not in the range of 0-100 it will print this statement and end the program
                        print('One of the values that you entered is not valid. Please enter a grade within the '
                              'range 0-100, Error\noccurred on line 1 in text file.')
                        exit(1)  # This ends the program if it fails the if statement
                print(round((prep / 14), 2), end=', ')

            def lab_score_average():  # This will compute the lab score average
                global lab
                lab = 0
                for i in (line[17:28]):
                    i = int(i)
                    if 0 <= i <= 100:  # This is checking to make sure that the grades are in the range 0-100
                        lab = lab + int(i)
                    else:  # if it is not in the range of 0-100 it will print this statement and end the program
                        print('One of the values that you entered is not valid. Please enter a grade within the '
                              'range 0-100, Error\noccurred on line 1 in text file.')
                        exit(1)  # This ends the program if it fails the if statement
                print(round((lab / 12), 2), end=', ')

            def post_lab_average():  # This calculates the post lab average of the student. It takes a letter and
                # converts the letter to a score that is an integer.
                global score
                score = 0
                for i in (line[28:39]):
                    if "A+" in i:
                        score += 100
                    elif "A" in i:
                        score += 95
                    elif "A-" in i:
                        score += 90
                    elif "B" in i:
                        score += 85
                    elif "C" in i:
                        score += 75
                    elif "D" in i:
                        score += 60
                    elif "F" in i:
                        score += 0
                    else:
                        print('Your file is not formatted to the standard of the program. On line 1 of your file, '
                              'you have\na score where a letter grade should be. Please check file and rerun the '
                              'program.')
                        exit(1)
                print(round((score / 12), 2), end=', ')

            def exam_average():  # This will compute the exam average for the student
                global exam
                exam = 0
                for i in (line[40:44]):
                    i = int(i)
                    if 0 <= i <= 100:  # This is checking to make sure that the grades are in the range 0-100
                        exam = exam + int(i)
                    else:  # if it is not in the range of 0-100 it will print this statement and end the program
                        print('One of the values that you entered is not valid. Please enter a grade within the '
                              'range 0-100, Error\noccurred on line 1 in text file.')
                        exit(1)  # This ends the program if it fails the if statement
                print(round((exam / 4), 2), end=', ')

            def overall_weighted_class_average():  # This will compute the overall class average for the student
                global weighted_class_grade
                global weighted_prep
                global weighted_lab
                global weighted_score
                global weighted_exam
                weighted_prep = ((prep / 14) * .10)  # This is calculating the weighted average for a
                weighted_lab = ((lab / 12) * .20)  # This is calculating the weighted average for b
                weighted_score = ((score / 12) * .10)  # This is calculating the weighted average for score
                weighted_exam = ((exam / 4) * .60)  # This is calculating the weighted average for exam
                weighted_class_grade = round((weighted_prep + weighted_lab + weighted_score + weighted_exam), 2)
                print(weighted_class_grade, end=', ')

            def letter_grade_for_class():  # This will take the weighted class grade and it will print that grade
                # according to the range
                letter = weighted_class_grade
                while True:
                    if 95 < letter <= 100:
                        print("A+")
                        break
                    elif letter == 95:
                        print("A")
                        break
                    elif 90 <= letter <= 94:
                        print("A-")
                        break
                    elif 85 < letter <= 89:
                        print("B+")
                        break
                    elif letter == 85:
                        print("B")
                        break
                    elif 80 <= letter <= 84:
                        print("B-")
                        break
                    elif 75 < letter <= 79:
                        print("C+")
                        break
                    elif letter == 75:
                        print("C")
                        break
                    elif 70 <= letter <= 74:
                        print("C-")
                        break
                    elif 65 < letter <= 69:
                        print("D+")
                        break
                    elif letter == 65:
                        print("D")
                        break
                    elif 60 <= letter <= 64:
                        print("D-")
                        break
                    elif letter <= 59:
                        print("F")
                        break

            def call_functions():  # This takes all the definitions and makes it into one definition
                student()
                preparation_assignment_average()
                lab_score_average()
                post_lab_average()
                exam_average()
                overall_weighted_class_average()
                letter_grade_for_class()
                return ''

            # After computing all the averages for the line of data it then writes it to a new file
            original_stdout = sys.stdout
            with open('test_file.csv', 'a') as file:
                sys.stdout = file
                for i in call_functions():
                    file.writelines('\n%s' % i)
                    sys.stdout = original_stdout

    except ValueError:  # displays when one of the letters is out of its index
        print('Sorry, one of the letters in the file is out of place. Please check the file again to make sure that \n'
              'the letter is not where the numbers are supposed to be. Check indexes 29-39. That is where the \n'
              'letter grades for the file should be.')
        exit(1)
    except FileNotFoundError:  # displays error if there is no file by that name
        print("Sorry, the current file that you have selected is not a File.")
        exit(1)
    except IndexError:  # this displays when there is no data in the file
        print('The file that you have selected does not contain any grades. Please check the file again.')
        exit(1)
    except PermissionError:  # this displays when you have the file open
        print('The file that you are trying to open is already open. Close the file and restart the program.')
        exit(1)


if __name__ == "__main__":
    main()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM