どうも今回はpythonでフィボナッチ数列を吐き出すプログラムを書いてみた話です。 お断り自分は素人もいいところのプログラミング初心者です。企業やグループでの開発経験もないです。そのためおかしな処理、非効率な処理、おかしな命名規則をしているかもしれませんがご了承ください。またかなり細かく説明するの結構長いです。 フィボナッチ数列とは フィボナッチ数列(フィボナッチすうれつ、(英: Fibonacci sequence) (Fn) は、次の漸化式で定義される: だそうです。要は前の値とその値を足した値が次の値になる数列のことです。 大体こんな感じを予想していました。 数列を入れる配列を作成 配列に対してi番目の値にi+1番目の値を足す 2の値を配列の最後に挿入 2,3を繰り返す ファイルに配列を書き込む ファイルはcsv初めはtxtにしていたのですが、もし今後何かに活用するならcsvの方が解析とかもしやすそうなので。あと書き込みも簡単なので。 importimport datetime # 日付取得 import os # makedirs import sys # 何用だっけ?モジュールだとかライブラリの読み込みです。pythonはまともに触ったのは初めてなのでよく知りません。今回はおまじないとして使います。 機能の選択などの設定 #設定の入力 print("1. n番目を求めますか?\n2. n番目番目まで全ての値を求めますか?\n1か2を入力してください。") All_cal = False chosen_input = input() if chosen_input == "1": All_cal = False else: All_cal = True print("nの値を入力してください。") time_cal = int(input())各変数の意味All_cal…出力の際に利用します。Falseなら全てを書き込まず、Trueなら全てをcsvに書き込みます。 これは「n番目の値を取得する」機能と「n番目までの全ての数列をcsvに書き込む」という2つの機能を持たせたため、ユーザに選択をさせます。ちょっとこの辺りのbool値の扱いが直感的でないので、いつか修正したい。 chosen_input = input()でユーザの選択を入力します。 if chosen_input == "1":if文で"1"が入力されたのかそれ以外かを判定します(1と2以外でもとりあえず進む様に)。1でも一応そのままAll_cal変数をFalseにします(最終的にプログラム全体をループさせるのでTrueになっている可能性がある。なりませんね。でも面倒なのでスルー)。2が入力された場合は全て書き込むのでTrueにします。 2024/02/18 そしてtime_calという計算回数を決定する変数を宣言します。ここでもユーザに入力を求めます。 演算部list_fibonacci = [0,1,] count = 1 for i in range(time_cal - 2): list_fibonacci.append(list_fibonacci[i]+list_fibonacci[i + 1]) i -= 1 print("\r" + str(count) + "回演算", end="") count += 1 print("演算終了")各変数の意味list_fibonacci…配列ですが一応。演算した値を入れてく箱 pythonでは「配列名 = [要素0,要素1]」で宣言できます。 list_fibonacci = [0,1,]最初は値を与えないといけないので、0と1だけ入れておきます。 count = 1countを1にしておく。for文の最後でインクリメントしておきます。 for i in range(time_cal - 2):for文で演算と挿入を繰り返します。繰り返す回数はユーザが選択した数にするため、演算のないfibonacci[0,1,]の2回分を引いておきます。 配列の添字はiを利用します。ただ2つ目の値を取得する際にiをインクリメントしているので、その後i -= 1で戻しておきます。こうしないとiがfor文によってもインクリメントされ回数がずれます。 print("\r" + str(count) + "回演算", end="")これは進捗状況の確認用です。正直演算は爆速なので一瞬です。ただ一応処理落ちとかの確認ができます。\rはその行の先頭に戻る、end=""は改行しないを意味して、同じ行にstr(count)(count変数をstr化)を繰り返し表示させます。 書き込み部if All_cal == False: # 1.n番目を抜き出す print(list_fibonacci[len(list_fibonacci) - 1]) else: # 2.全ての値を求める # 書き込み count = 1 for n in list_fibonacci: write_csv(n, count, csv_file_title) count += 1 print("\n書き込み完了")ここでAll_cal変数の内容で分岐します。 if All_cal == False: # 1.n番目を抜き出すAll_calがfalseということはn番目だけでいいので配列の最後の値がわかればいい。したがってlen()で配列の全要素数を取得して1を引いた値を添字として、配列の最後の値を表示する。ここで-1するのは配列の添字は0が先頭だがlen()で取得したサイズは1から数えた数のため。 else: # 2.全ての値を求めるAll_calがtrueということは全ての値をcsvに書き込みます。 ここで書き込み機能は別関数にします。またwrite_csvの行の最後にcsv_file_titleという宣言してない変数がありますがこれはパス関連の問題で別の場所で宣言しているのでそちらの説明をします。 パスの設定実は機能の選択などの設定のすぐ下にあるコードなのですが、複雑になりそうなので後回しにしました。 csv_file_title = f"fibonacci_{datetime.datetime.now().strftime('%m_%d_%H:%M:%S')}.csv" # パスの設定 if getattr(sys, 'frozen', False): executable_path = sys.executable parent_path = os.path.dirname(executable_path) # ファイルフォルダ作成 os.makedirs(f"{parent_path}/csv_files", exist_ok=True) csv_file_title = f"{parent_path}/csv_files/{csv_file_title}" with open(csv_file_title, 'w') as f: f.write("time,value\n") else: os.makedirs("csv_files", exist_ok=True) csv_file_title = f"csv_files/{csv_file_title}" with open(csv_file_title, 'w') as f: f.write("time,value\n")csv_file_title = ……}.csv"これはさっきのcsv_file_title変数の定義ですね。これはcsvファイルを作成するパスを示しています。 if getattr(sys, 'frozen', False):これは今実行しているのが.pyファイルなのかexeなどの実行ファイルになっているを判定しています。(多分)もし実行ファイルの場合はどうやらパスの指定を変えないといけないそうなので、それを実装していきます。 executable_path = sys.executableこれはexecutable_path変数にその実行ファイルのパス(sys.executable)を代入しています。 2024/02/18 csvファイル用のフォルダは実行ファイルのある階層に作成したいので実行ファイルの親フォルダのパスを取得します。os.path.dirname(executable_path)これで()内のファイルの親フォルダを取得できる。 2024/02/18 os.makedirsというのはフォルダを作成する機能です。基礎構文は以下の通り。 os.makedirs("パス",) # 既にフォルダが存在する場合でもエラーを起こさないように以下の引数をつける os.makedirs("パス", exist_ok=True)ちなみにmakedirsは中間フォルダも再起的に作成するため、便利だそう。 f"{parent_path}/csv_files"とは文字列を示す""の前にfがついているのは文字列内で変数を扱うための記述です。この場合、{}で囲った範囲は変数として扱えます。今回は先ほど実行ファイルのある親フォルダのパスに/csv_filesというフォルダを作成しています。 csv_file_title = f"{parent_path}/csv_files/{csv_file_title}"これは先ほどの親パスにcsvファイルの名前も追加したcsvのパスになります。(_titleになっているのにパスが入るのはちょっとアレかもしれませんが…)ここで最後の{csv_fiel_title}にはfibonacci_日付が入っています。 with open(csv_file_title, 'w') as f:with文はファイル操作や通信などの開始時の前処理と終了時の後処理など必須となる処理を自動で実行してくれるものになる文だそう。 上記のcsv_file_titleというタイトルのファイルを作成(最後が.csvになるためファイル形式はそのまま)します。'w'は上書きという意味です。ちょっと自分でもよく分からないのですが、ファイル名には親フォルダのパスなどが入らず「fibonacci_02_17_15:33:57.csv」となっています。よく分からん。おそらく、パスを含んだ文字列ではなく、パスのデータとして扱っているから最後の/以降がファイル名とし設定されてます。 f.write("time,value\n")fとした物にwriteで()を書き込みます。今回は"time,value\n"というカラムタイトルをファイルの初期化の意味も含めて実行します。\nは改行の意味です。 else:elseということは.pyファイルを実行しているのでそのままフォルダを作成できます。先ほどとは違い、csv_filesというフォルダをそのまま作成しています。それ以外は同じです。 os.makedirs("csv_files", exist_ok=True) csv_file_title = f"csv_files/{csv_file_title}" with open(csv_file_title, 'w') as f: f.write("time,value\n")このコードの必要性これは書き込むファイルやフォルダのパスを設定しているのですが、本来ならここまで多くはなりません。ただし今回はpyinstallerというツールでpythonのない環境でも動作する単一の実行ファイルを作りました。これの影響でファイルが作成されない問題が発生したため、パスを明確に設定しています。 このあとは演算部につながっています。 書き込み部2(write_csv関数)これで書き込み部の章での最後の謎変数「csv_file_title」がcsvファイルのパスを示していることがわかりました。ではいよいよ書き込みです。 pythonではそのコードより上にある関数を使用するので、こんか所謂main関数的な処理(ここまでの処理)は直に書いてます。importたちと今まで処理の間に以下を突っ込みます。 def write_csv(n, count, file_name): with open(file_name, 'a') as c: c.write(str(count) + "," + str(n) + "\n") print("\r" + str(count) + "回書き込み", end="")def write_csv(n, count, file_name):関数の定義です。pythonの関数は以下の通り。cなどの{}はインデントで行うよう。また引数も型の宣言が不要なよう。 def 関数名(引数1, 引数2): //処理 //関数外の処理(n, count, file_name)今回使ってる引数は上の3つ。nは書き込む数列の値、countは何番目か用の番号です。file_nameはファイルに書き込む時のファイルの特定用。 with open(file_name, 'a') as c:先ほどの様にファイルに対してopenします。今回は'a'としています。これは追記の意味で、ファイルの初期化で書いた"time,value\n"を消さないように、さっき書いた1個前の値を消さない様にするためです。 countのインクリメントは関数の呼び出し元である書き込み部で行なっています。 print("\r" + str(count) + "回書き込み", end="")これは書き込みの進捗を表示します。演算に関しては一瞬なのですが、nを10000とかにすると結構遅くなります。なので書き込みの進捗は確認しやすい方がいいです。 最初のwhile順番的にはかなり前のコードなのですが、最後の方がわかりやすいので。 while True: //全体の処理 print("もう1度計算しますか?y/n") if input() != "y": break普通ならdo~whileで少なくとも1度は実行を実装するのですが、pythonにはdo~whileがないので、while Trueで無限ループさせ、ifで抜けるという方法を取ります。 print("もう1度計算しますか?y/n")でy以外(!= y)が入力さればbreakして終了します。 まとめ長々とお付き合いいただきありがとうございました。 今回はいつものようにプログラミング言語の基礎の話はしなかったので、いつかpythonシリーズも作りたいなぁ~と思ってます。それと最初はswiftで書いたんですけど、型の関係で大きな値を扱いづらかったのでpythonにしました。やっぱり言語ごとに向き不向きありますね。pythonはアルゴリズムというか処理の方法に集中できる印象です。 一部修正点まとめ(最終追記:2024/02/18)All_calの設定を最適化 sys.executableの親フォルダを直接代入 n番目のみ表示する際にフォルダが作成される問題を修正 githubで公開一応noteで晒したんだから公開しても変わらんかと思い、publicにしようと思います。過去のバージョンのコードがひっどいのであれですが一応。というかコミットの仕方とかgitの使い方がわからず無茶してます。 参考
Pythonでディレクトリ(フォルダ)を作成するmkdir, makedirs | note.nkmk.me
Pythonで新しいディレクトリ(フォルダ)を作成するには標準ライブラリosモジュールのos.mkdir()またはos.m
note.nkmk.me
↑のページだけでなく関数などの解説も参考にさせていただきました。 https://www.perplexity.ai/
ChatGPT
A conversational AI system that listens, learns, and challeng
chat.openai.com
その他多くの解説サイト様、ありがとうございます。 (责任编辑:) |