0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Python初学者】楽天価格チェッカーを作ってみた ⑦ ― パス管理・設定(path_helper.py & config.py)

0
Posted at

【Python初学者】楽天価格チェッカーを作ってみた ⑦ ― パス管理・設定(path_helper.py & config.py)

はじめに🐰

Python初学者のわたしが覚えるために、学んだことを整理し、理解を深めるために記事を書いています。
私が実際にやってみて、悩んだ部分や過程などを残していきます🐥

今回は utils/path_helper.pyconfig.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から始まる ため、この考え方に慣れておくと理解しやすくなります😊
💡 ここで少し気づきがありました

自分でまとめながら理解できたのですが、最初は少し不思議でした😊
普段ファイルを探すときは、
フォルダ → 子フォルダ → さらに子フォルダ
というように、下の階層へ進んでいく イメージが多いですよね!!
でも今回の parentparents[] は逆で、今いる場所 → 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)
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?