2

重複の可能性:
Pythonの「驚き最小の原則」:可変のデフォルト引数

さて、私はPythonを学ぼうとしています。数学期前にPythonクラスの紹介をした友人がいて、彼は私に古い課題をすべて教えてくれました。私は特に厄介な問題を抱えており、それは非常に単純なはずだと思いますが、私の問題がどこにあるのか理解できないようです。皆さんの考えをご覧ください。

プログラムは、grades.txtというファイルから読み取ることになっています。ファイルは次のとおりです。

2
John Doe
82
100
57
0
Jane Smith
91
12
45
81
0

このファイルの形式は次のとおりです。最初の行は学生の数です。次に、生徒の名前とそれに続く成績があります。ゼロは、生徒の成績リストの終わりを表します。私は知っています、私は知っています...そのようにすることはあまり意味がありませんが、それはこれが読む方法です。

とにかく、これが私がこれまでに書いたコードです。

#!/usr/bin/env python

class students():
        def __init__(self, fname='', lname='', grades=[]):
        self.firstName = fname
        self.lastName = lname
        self.gradeBook = grades

def lineCheck(lineText):
     try:
         int(lineText)
         return True
     except ValueError:
         return False

inFile = "grades.txt"
outFile = "summary.txt"

count = 0
numStudents = 0

studentList = []
check = False

with open(inFile, "r") as file: 
    for line in file:
        if(count == 0):
            numStudents = line.strip()
        else:
            lineRead = line.strip()
            check = lineCheck(lineRead)
            if(check == False):
                studentName = lineRead.split()
                fName = studentName[0]
                lName = studentName[1]
                temp = students(fName, lName)
            else:
                if(lineRead != '0'):
                    temp.gradeBook.append(lineRead)
                elif(lineRead == '0'):
                    studentList.append(temp)

        count += 1
file.close()

for student in studentList:
    print student.firstName + " " + student.lastName
    print student.gradeBook

このコードでは、私にとって期待される出力は、プログラムの最後のforループにあります。私はこのようなものを見ることを期待しています:

John Doe
['82', '100', '57']
Jane Smith
['91', '12', '45', '81']

しかし、私が得ている出力はこれです:

John Doe
['82', '100', '57', '91', '12', '45', '81']
Jane Smith
['82', '100', '57', '91', '12', '45', '81']

私はこれをずっと見つめていましたが、これは非常に単純なことだと感じています。しかし、私はPythonに不慣れで、そのニュアンスのすべてにまだ完全に慣れていないので、経験豊富な人がここで何が起こっているのかを理解できるかもしれません。私はあなたが私に与えることができるどんな助けでも本当に感謝します。ありがとう。

4

2 に答える 2

3

あなたの実際の問題[]は、デフォルトの引数として使用していることです。デフォルトの引数は一度作成され、関数に「添付」されるため、新しい学生オブジェクトを作成するたびに、同じ成績リストを再利用しています。代わりに次のようなものが必要です。

def __init__(..., grades=None):
    if grades is None:
        self.gradeBook = []
    else:
        self.gradeBook = grades

さて、別の批評をさせてください。:)

コードにスペースとタブの組み合わせが含まれているようです。空白が重要なPythonのような言語では、これは本当に悪いことです. 使用しているエディタはわかりませんが、キーを押すTabと常に 4 つのスペースが挿入されるように設定する方法を見つける必要があります。

残りの部分はそれほど重要ではありませんが、他の Python プログラマーと仲良くするのに役立ち、コードをより単純にするのに役立つかもしれません。


これはいくつかの場所で行います。

if(check == 0):

括弧は不要です。

if check == 0:

次のものがあります。

if(lineRead != '0'):
    ...
elif(lineRead == '0'):
    ...

elif ...ただし、これらのうち 1 つだけが trueになる可能性があります (等しいか等しくないかのいずれかです) else。しかし、それは二重否定につながります(そうではありません!=...)ので、ブランチを交換しましょう。

if lineRead == '0':
    ...
else:
    ...

check = lineCheck(lineRead)
if(check == False):

変数は 1 回しか使用しcheckないため、あまり必要ありません。また、以下と比較したり、直接比較しTrueたりすることを避ける方が一般的です。False

if not lineCheck(lineRead):

しかし、これはよく読めません。アクションを実行する関数は動詞として名前を付けるのが最適であり、何かを検証する関数 (このようなもの) は、名前を付けると適切に聞こえis_whateverます。変数は、英語で話しているように名前を付けたいと思います。「行の読み取り」について話すことはあまりありませんが、「行の読み取り」、または単に「行」について話す場合があります。

ああ、Python スタイル ガイド、PEP 8では、キャメルケースの代わりにアンダースコアを使用することをお勧めします。

if not is_numeric(line):

クラス名は慣習的に UppercaseCamelCase で書かれ、一種のものを記述するため、単数でなければなりません。(「どんな種類のペットを飼っていますか?」「猫です。」) そしてobject、常に から継承する必要があります。そうしないと、Python の初期の時代に由来し、少し粗雑な「古いスタイルのクラス」を取得することになります。

そして、私がそうしている間、学生が名前を持っていないことはあまり意味がありません. first と last に分割しようとしないほうがよいですが。

class Student(object):
    def __init__(self, name, grades=None):
        ...

今は問題ありませんが、すべての「メイン」コードを呼び出した関数に入れてmain実行すると後で役に立ちます。mainそうすれば、すべてをすぐに実行することなく、他のコード (たとえば、テストなど) からインポートできます。

if __name__ == '__main__':
    main()

__name__は現在の「モジュール」の名前にすぎず'__main__'python file.py.


いくつかの深刻なつまらないものを選んだ後、私はこれになりました:

class Student(object):
    def __init__(self, name, grades=None):
        self.name = name
        if grades is None:
            self.gradebook = []
        else:
            self.gradebook = grades

def is_numeric(s):
    try:
        int(s)
        return True
    except ValueError:
        return False

def main(infile, outfile):
    count = 0
    num_students = 0

    students = []

    with open(infile, "r") as f:
        for line in f:
            line = line.strip()

            if count == 0:
                # This is the first line
                num_students = int(line)
            elif not is_numeric(line):
                # Non-numbers are names of new students
                cur_student = Student(line)
            elif line == '0':
                # Zero marks the end of a student
                students.append(cur_student)
            else:
                cur_student.gradebook.append(line)

            count += 1

    for student in students:
        print student.name
        print student.gradebook

if __name__ == '__main__':
    main("grades.txt", "summary.txt")

上記以外の小さなことをいくつか行いました。それらが理にかなっていることを願っています。

  • file組み込み関数の名前です。Python では名前を使用できますが、後でビルトインを使用しようとすると驚かれることでしょう。これfは、短時間だけ開いているファイルを参照する一般的な方法です。

  • temp意味が覚えにくい!そのような変数名を付けないようにしてください。ここでcur_student、「cur」は「current」の一般的な略語です。

  • 必要ありませんf.close(); withブロックがそれを行います。実際、それが の要点ですwith

  • line.strip()何が起こっても電話するので、ループの最初に入れます。これにより、すべてのifを 1 つにまとめることができるため、何がいつ起こっているのかを簡単に追跡できます。

  • ご指摘のとおり、これはかなり奇妙なファイル形式であるため、簡単なコメントをいくつか追加しました。

それが何かを意味するなら、これは私がそれを書く方法にずっと近いです。

新しい人がプログラミングを始めるのを見るのはいつもうれしいです! Python をお楽しみください :)

于 2013-01-17T07:50:19.353 に答える
2

使用する

class students():
    def __init__(self, fname='', lname='', grades=None):
        self.firstName = fname
        self.lastName = lname
        self.gradeBook = [] if grades is None else grades

問題はデフォルト引数です[]

于 2013-01-17T07:34:13.460 に答える