`with` でファイルを開く
変数はプログラムが終わると消えますが、ファイルは残ります。open(path, mode) はファイルオブジェクトを返し、mode で目的を指定します。"r" は読み込み(既定)、"w" は書き込み、"a" は追記です。ファイルは必ず with ブロックで開きましょう:with open(path) as file:。ブロックが終わると、中でエラーが起きても Python が自動でファイルを閉じるので、データが失われたり書きかけで残ったりしません。どのコンピューターでも同じように読み書きできるよう、encoding="utf-8" を指定します。
# Write a file, then read it back
with open("fills.txt", "w", encoding="utf-8") as file:
file.write("AAPL,184.25,200\n")
file.write("MSFT,410.20,50\n")
with open("fills.txt", encoding="utf-8") as file:
text = file.read()
print(repr(text)) # 'AAPL,184.25,200\nMSFT,410.20,50\n'1行ずつ読む
file.read() はファイル全体を1つの文字列で返します。もっとよく使うのは、ファイルオブジェクトそのものをループすることで、1行ずつ取り出せ、メモリに収まらない大きなファイルでも使えます:for line in file:。各行の末尾にはまだ \n が付いているので、line.strip() で整えます。空行は整えると空文字列 "" になり、これは偽なので if text: で読み飛ばせます。全行を一度に欲しいときは file.readlines() や text.splitlines() がリストを返します。
# Read line by line, skipping blank lines
with open("fills.txt", "a", encoding="utf-8") as file:
file.write("\n") # a blank line
total = 0.0
with open("fills.txt", encoding="utf-8") as file:
for line in file:
text = line.strip()
if not text:
continue
symbol, price, quantity = text.split(",")
total += float(price) * int(quantity)
print(round(total, 2)) # 57360.0書き込みと追記
file.write(text) は渡した文字列をそのまま書き込み、文字数を返します。改行は追加されないので、各行の末尾に自分で "\n" を付けます。モード "w" はまずファイルを空にし(なければ作成し)、既存のファイルを "w" で開くと古い内容が捨てられます。モード "a" は既存の内容を残して末尾に追加します。書き込めるのは文字列だけなので、数値は先に変換します。たとえば f"{price:.2f}" のような f 文字列を使います。
# "w" starts over, "a" adds to the end
with open("log.txt", "w", encoding="utf-8") as file:
file.write("start\n")
with open("log.txt", "a", encoding="utf-8") as file:
file.write("order 1 filled\n")
file.write(f"pnl {12.5:+.2f}\n")
with open("log.txt", encoding="utf-8") as file:
print(file.read().splitlines()) # ['start', 'order 1 filled', 'pnl +12.50']
with open("log.txt", "w", encoding="utf-8") as file:
pass # opening with "w" emptied it
with open("log.txt", encoding="utf-8") as file:
print(repr(file.read())) # ''パスと存在しないファイル
"fills.txt" のような相対パスは、プログラムの現在のフォルダーから探されます。区切り文字を気にせずパスを組み立てるには os.path.join(folder, name) を使います。存在しないファイルを読み込みで開くと FileNotFoundError になり、ファイルがないことが想定内なら try/except で受け止められます。小さなファイルなら、pathlib.Path(path).read_text() と .write_text(text) が、開く・読む(書く)・閉じるを1回の呼び出しで行います。
import os
from pathlib import Path
# A missing file is an exception you can handle
def count_lines(path):
try:
with open(path, encoding="utf-8") as file:
return len(file.read().splitlines())
except FileNotFoundError:
return 0
print(count_lines("fills.txt")) # 3
print(count_lines("nope.txt")) # 0
# pathlib does open + read + close in one call
path = Path(os.path.join(".", "fills.txt"))
print(path.read_text(encoding="utf-8").splitlines()[0]) # AAPL,184.25,200"w" を使うと、元に戻せずデータが消えます。1行に1レコード、フィールドはカンマ区切りといった単純な形式を決め、読み込み側と書き込み側を一緒に作って食い違わないようにします。次に学ぶ CSV 形式は、まさにこの考え方を正式にしたものです。with open(path, mode, encoding="utf-8") as file::ファイルを開き、必ず閉じるfor line in file::1行ずつ読む。line.strip():改行を取り除く"w"はファイルを空にし、"a"は追記する。writeは改行を付けない
次は CSV ファイルです。価格や約定の表を保存する標準的な方法を学びます。
ラボ:採点される内容
read_symbolsでファイルからウォッチリストを読み込む25点parse_tradesで約定ファイルをタプルに変換する25点write_reportで損益レポートを保存する25点append_linesでログを消さずに追記する25点