【Python初学者】楽天価格チェッカーを作ってみた ⑦ ― パス管理・設定(path_helper.py & config.py)
はじめに🐰
Python初学者のわたしが覚えるために、学んだことを整理し、理解を深めるために記事を書いています。
私が実際にやってみて、悩んだ部分や過程などを残していきます🐥
今回は utils/path_helper.py と config.py をまとめて解説します!
どちらも「設定・定数を管理する」役割のファイルです!
短いコードですが、実用的なプロジェクトでは欠かせない考え方が詰まっています😊
本日のゴール⚽️
-
pathlib.Pathを使ったパス操作の基本を理解する -
sys.frozenで「Python実行」と「exe実行」を判定する仕組みを知る - 定数を
config.pyにまとめる理由を理解する
path_helper.py のコード
from pathlib import Path
import sys
def get_root_path() -> Path:
# exe(実行ファイル)として動いているか判定する
# getattr(オブジェクト, 属性名, デフォルト値) → 属性がなければデフォルト値を返す
if getattr(sys, "frozen", False):
# exeの場合:exeファイルがある場所を「ルート」とする
return Path(sys.executable).parent
else:
# Pythonスクリプトの場合:このファイルの2つ上の階層がルート
return Path(__file__).parents[1]
def get_env_path() -> Path:
# .envファイルのパスを返す(ルート直下)
return get_root_path() / ".env"
config.py のコード
# 除外するキーワード(中古・訳ありなどを検索結果から外す)
EXCLUDE_KEYWORDS = ["中古", "訳あり", "ジャンク", "used", "アウトレット"]
# CSV サマリーセクションのタイトル
CSV_REPORT_TITLE = "■ 検索統計レポート"
# CSV サマリーのヘッダー(辞書形式)
CSV_SUMMARY_HEADERS = {
"keyword": "検索キーワード",
"min": "最安価格",
"avg": "平均価格",
"max": "最高価格",
"count": "有効ヒット件数"
}
# CSV 商品一覧セクションのタイトル
CSV_LIST_TITLE = "■ 商品詳細(価格の安い順)"
# CSV 商品一覧のヘッダー
CSV_PRODUCT_HEADERS = ["価格", "商品名", "ショップ名", "商品URL", "平均レビュー", "レビュー件数"]
コードの詳細解説
① pathlib.Path とは?
Pythonでは、ファイルやフォルダの場所を表す文字列のことを パス(path) と呼びます🐣
pathlib はファイルパスを扱うモジュールです!
昔は os.path.join() などを使っていましたが、pathlib.Path を使うとよりシンプルに書けます。
from pathlib import Path
# パスの結合
path = Path("/Users/eriko") / "Documents" / "data.csv"
# → /Users/eriko/Documents/data.csv
# os.path.join() との比較(同じ意味)
import os
path = os.path.join("/Users/eriko", "Documents", "data.csv")
/ を使ってフォルダをつなげて書けるので、とても直感的です🐣
pathlib でできること😊
- ファイルを読む
- ファイルを保存する
- フォルダを作る
② __file__ と parent / parents[]
__file__ は、今書いているPythonファイル自身の場所を表すものです🐣
たとえば、今回の path_helper.py が次の場所にあるとします!
ec_price_checker/
├─ utils/
│ └─ path_helper.py
├─ .env
└─ main.py
このとき __file__ は、次の場所を指しています。
__file__
↓
/ec_price_checker/utils/path_helper.py
これは 「自分自身(このファイル)の場所」 です🐣
次に Path() で囲んでみます!
Path(__file__)
↓
/ec_price_checker/utils/path_helper.py
見た目は変わりません!
ここでやっているのは、ただの文字列を「パスとして扱える形」に変換しているだけです🐣
まだ場所は移動していません!
ここで .parent を使うと、1つ上のフォルダへ移動できます🏃
Path(__file__).parent
↓
/ec_price_checker/utils
parent は 親フォルダ(1つ上) を取得するものです🐣
さらに上の階層へ移動したいときは、parents[] を使います🏃🏃
Path(__file__).parents[0]
↓
/ec_price_checker/utils
これは .parent と同じ意味です🐣🐣
Path(__file__).parents[1]
↓
/ec_price_checker
これは 2つ上のフォルダ を取得しています🏃🏃🏃
ここで少し注意です👇
parents[] は 0から数える ため、
parents[0] → 1つ上
parents[1] → 2つ上
parents[2] → 3つ上
となります!!
Pythonでは配列の番号も 0から始まる ため、この考え方に慣れておくと理解しやすくなります😊
💡 ここで少し気づきがありました
自分でまとめながら理解できたのですが、最初は少し不思議でした😊
普段ファイルを探すときは、
フォルダ → 子フォルダ → さらに子フォルダ
というように、下の階層へ進んでいく イメージが多いですよね!!
でも今回の parent や parents[] は逆で、今いる場所 → 1つ上 → さらに1つ上
というように、上の階層へ戻っていく 動きになります🥺
この「いつもの感覚と逆の動き」が、最初に少し混乱したポイントでした😂
でも理解すると、
「今いる場所を起点に、必要な場所まで戻る」
という考え方なんだと分かって、すごくスッキリしました✨
③ sys.frozen でexeかPythonかを判定する
if getattr(sys, "frozen", False):
return Path(sys.executable).parent
else:
return Path(__file__).parents[1]
このプロジェクトは PyInstaller を使ってexeファイルにもできます!
exeとして実行されるとき、sys.frozen という属性が自動的に設定されます🐣
sys.frozen は exe実行時だけ存在する属性 です!
- Python実行 → 存在しない
- exe実行 → True
そこで getattr(sys, "frozen", False) を使い、あればその値、なければ False⚡️
を返すようにして、安全に判定しています🐣
判定後は取得する場所を切り替えます!!
- exe実行 →
Path(sys.executable).parent
→ exeファイルがある場所 - Python実行 →
Path(__file__).parents[1]
→ Pythonファイルを基準に2つ上のフォルダ
つまり、実行方法に合わせて、正しいルートフォルダを取得する仕組みになっています✨
④ Path の / 演算子でパスを組み合わせる
次にこの部分です🐣
def get_env_path() -> Path:
return get_root_path() / ".env"
ここでは Path の / 演算子 を使って、パスをつなげています。
たとえば、
get_root_path()
が次の場所だったとします!
/ec_price_checker
そこに .env をつなげると、
get_root_path() / ".env"
↓
/ec_price_checker/.env
となります!
文字列を足しているように見えますが、Path 型同士を自然につなげてくれる便利な書き方です!
つまりこのコードは、
「ルートフォルダの中にある .env ファイルの場所を取得する」
という意味になります😊
⑤ config.py に定数をまとめる理由
config.py は、変わらない値(定数)をまとめて管理するファイルです🐣
EXCLUDE_KEYWORDS = ["中古", "訳あり", "ジャンク", "used", "アウトレット"]
たとえば除外キーワードを追加したいときも、config.py を1か所直すだけでOKです🥺
各ファイルにバラバラに書くより、 設定はここを見ると場所が決まっている方が、
修正もしやすく管理もしやすくなります😊
またPythonでは、定数は
EXCLUDE_KEYWORDS
のように 大文字 + アンダースコア で書くのが慣習です!
変数名を見ただけで、 「これは設定として使う値なんだな」
と分かりやすくなります✨
まとめ
| 学んだこと | ポイント |
|---|---|
pathlib.Path |
os.path より直感的なパス操作 |
__file__ |
このファイル自身のパスを取得する |
parents[N] |
N個上の階層のパスを取得する |
getattr(obj, attr, default) |
属性が存在しない場合にデフォルト値を返す |
sys.frozen |
exeで実行されているか判定するフラグ |
Path / "文字列" |
/ 演算子でパスをつなぐ |
config.py に定数をまとめる |
変更箇所を1ファイルに集約して管理しやすくする |
| 定数は大文字のスネークケース |
EXCLUDE_KEYWORDS のように書くのがPythonの慣習 |
次回はいよいよ最終回! main_flow.py(全体を統括するクラス)を解説します🐣🐣
🐣シリーズ一覧🐣
- ① プロジェクト全体像とフォルダ構成
- ② 楽天APIリクエスト(rakuten_api.py)
- ③ フィルタリング・並び替え(price_list_builder.py)
- ④ 統計計算(price_stats.py)
- ⑤ CSV保存(csv_saver.py)
- ⑥ ポップアップUI(popup.py)
- ⑦ パス管理・設定(path_helper.py & config.py) ← 今回
- ⑧ 全体統括(main_flow.py)