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のフォルダ構成について考える

Last updated at Posted at 2025-04-28

はじめに

Pythonで色々コードを書いているときに

  • どこに何の処理が書いてあるのかわかりづらい
  • 処理/機能毎にフォルダ分けしておきたい

と思ったので、個人的なメモを残しておく。

フォルダ構成の必要性

  • 可読性・保守性の向上
    • コードの構造を視覚的に表現することで、目的の処理がどこに配置されているか分かりやすく、デバッグやメンテナンスが容易となる
  • 管理効率化
    • 階層構造を明確にすることでファイルを探す手間が省け、プロジェクト全体を効率的に管理できる
  • 規模が大きくなっても耐えられる
    • 目的別にフォルダ構成が分けられていると、機能追加等による拡張がしやすくなる

Pythonフォルダ構成(例)

● 構成

[ project ]
├ [ project ]       # ソースコードを保管するフォルダ
│ ├ [ config ]
│ │ └ settings.py    # 設定ファイル
│ ├ [ package1 ]
│ │ ├ __init__.py ※
│ │ └ moduleA.py
│ ├ [ package2 ]
│ │ ├ __init__.py ※
│ │ └ moduleB.py
│ ├ __main__.py
│ └ main.py
├ [ tests ]        # テストのためのコードを保管するフォルダ
│ └ test.py
├ [ doc ]         # プロジェクトにおけるドキュメントを保管するフォルダ
└ Readme.md

※昔はパッケージには必ず init.py が必要だったけど、最近(Python 3.3以降)は必須でなくなりました。ただ、互換性を考えて今でも置いておくのが一般的です。

メイン処理

main.py
from .package1 import moduleA
from .package2 import moduleB

def main():
    moduleA.func("kinouA")
    moduleB.func("kinouB")

if __name__ == '__main__':
    main()
__main__.py
if __name__ == '__main__':
    from .main import main
    main()

各パッケージ(サブモジュール)

moduleA.py
def func(msg):
    print("A:",msg)
    return

if __name__ == '__main__':
    func()
moduleB.py
def func(msg):
    print("B:",msg)
    return

if __name__ == '__main__':
    func()

● 実行

project $ python -m prj
A: kinouA
B: kinouB

● テスト

test.py
import unittest
from unittest.mock import patch
from prj.package1 import moduleA

class TestUser(unittest.TestCase):
    @patch('builtins.print')
    def test_func_prints_message(self, mock_print):
        moduleA.func("kinouA")
        mock_print.assert_called_once_with("A:", "kinouA")

if __name__ == "__main__":
    unittest.main()
project $ python -m unittest discover test
.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK

補足

標準出力と戻り値の両方をテストする場合

moduleA.py
def func(msg):
    print("A:",msg)
    return True
test.py
class TestFunc(unittest.TestCase):
    @patch('builtins.print')
    def test_func_prints_message_and_returns_true(self, mock_print):
        # Act
        result = moduleA.func("Hello")
        # Assert: printの呼び出しをチェック
        mock_print.assert_called_once_with("A:", "Hello")
        # Assert: 戻り値をチェック
        self.assertTrue(result)

テスト関数の名前付け、基本ルール

  • 必ず test_ から始める(unittestが自動で見つけるため)
  • 何をテストしているかが人間に読んでわかるようにする
  • 動作+条件+期待結果 をなるべく含めると良い

参考

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?