nikkie-ftnextの日記

イベントレポートや読書メモを発信

私見:Pythonプロジェクトの3類型(ver 2024.09)

はじめに

(私はアイドルに)なれないの?😭😭😭 nikkieです。

Pythonの開発環境に興味を持ち、直近3ヶ月くらいこのブログでたびたびアウトプットしてきました。
Pythonの開発環境は、仮想環境 + その管理を引き受けるツールと捉えており、ツールは乱立しているように映ります1
具体的なツールを見るというのもやっているのですが、Python依存ライブラリをインストールした環境でどのようなファイル配置でも実行できるというのが1つ特徴的かもと思い至り、今回の記事にしてみました。

目次

「プロジェクト」

私たちPython使いがふだん書いているPythonコードをなんと呼ぶか、コミュニティ内にも統一見解はあまり形成されている感がないのですが、Pythonパッケージングの用語集を引きます。
https://packaging.python.org/ja/latest/glossary/#term-Project

ライブラリ、フレームワークスクリプトプラグイン、アプリケーション、ないし一連のデータもしくはその他のリソース、または、これらの組み合わせで :term:配布物 <Distribution Package>として意図的にパッケージされたもの。(ママ)

この記事では「配布物として意図的にパッケージされた」の部分は採用しません
この記事における「プロジェクト」は、私たちがふだん書いているPythonコード(スクリプト、アプリケーション、フレームワークなどなど)で、場合によっては配布したいこともあるというものです。
このプロジェクトに類型があるという見方を書いていきます。

  • 1ファイル・配布しない:スクリプト
  • 複数ファイル群・配布しない
  • 複数ファイル群・配布する
    • 「1ファイル・配布する」はここに包含されると考えています

Python以外の言語に目を向けると、Rustではcargo initがあり、バリエーションに富んだプロジェクトは成立しにくいように思います。
「さまざまな構成のプロジェクトがありうる」というのがPythonの特徴と言えるのかもしれません。

1️⃣スクリプト

拡張子が.pyのファイル(例 script.py)を書くだけで、Python処理系に実行させられます。
python script.pyですね。
script.pyのところはファイルへのパスであればよいです(python scripts/awesome.py)。

Pythonのドキュメントでは以下(python <script>のドキュメント)。
https://docs.python.org/ja/3/using/cmdline.html#cmdarg-script

script 内の Python コードを実行します。

スクリプトを書いて手軽に実行できる点で、Pythonという言語は高く評価されていると感じます。
一例としては、PyCon JP 2019のキーノート2
コーリー・アルソフ氏(『独学プログラマー』著者)は、JavaPythonの「Hello, world」を比較します

さて、Pythonには幅広い標準ライブラリがありますが、スクリプトサードパーティのライブラリを使いたい場合が往々にしてあります。
ここで導入されるのが、仮想環境3
要は、スクリプトに必要な依存を環境に用意することでスクリプト内でimportできるようにして、処理系に実行させようというわけですね。

2️⃣再配布しないプロジェクト

Webフレームワーク(例:Django)を使ったWebアプリケーション作成や、いくつもスクリプトを書いて機械学習をしていくような場合を想定しています。

Djangoを使ったWebアプリ自体はインストールしない

Djangoや他の依存ライブラリを仮想環境にインストールして、私たちのソースコードを動かします

使うライブラリは(スクリプトのときと同様)仮想環境にインストールしますね。

「再配布しない」とは、プロジェクトをインストール可能にしないということです。
例えば、Djangoを使ったアプリケーション4や、機械学習のコンペで書いたコードは、そのまま他の人の環境にpip installできるようにはなっていません。
後述する方法でインストール可能にできるのですが、インストールしたいシーンは少なく、そうするメリットはほとんどないように思われます

3️⃣再配布するプロジェクト

karaageさんによるunko(クソライブラリ)のような、インストール可能なプロジェクトです。

pyproject.tomlを書いてインストール可能にします5

再配布するプロジェクトを開発するときは、仮想環境にeditableインストールします。
pip install -e . (eは、editableのe)
ref: https://pip.pypa.io/en/stable/cli/pip_install/#cmdoption-e

依存ライブラリと同じようにpip install(editableではない)だと、プロジェクト内のソースコードを変更するたびにインストールが必要です。
一方、editableインストールすれば、ソースコードを変えても再インストール不要で追従します。

Future works (パッケージマネージャを考えていきたい)

ここにまとめたのは、Pythonプロジェクトと言っても、ファイルの数や再配布したいかによって類型があるということです。
そして今後考えていきたいのは、類型ごとに適したツール(パッケージマネージャ)があるのではないかということ6

例えば、スクリプトのケースでは、仮想環境の操作が煩雑です。
この領域では、inline script metadataをサポートしたpipx(やuv7)に仮想環境の操作を任せることができ始めており、私としてはこの流れは大歓迎です!

スクリプト以外のケースですが、例えばPoetryでは再配布したい/したくないを切り替えて環境構築できることを知りました。
https://python-poetry.org/docs/pyproject/#package-mode
一方、PoetryはPEP 621サポートが進んでおらず、プロジェクトのメタデータを現状はPoetry流なオレオレwayで書かざるを得ません。
逆に、PEP 621をサポートしているPDMやHatchでは、再配布したい/したくないを切り替えられるかはまだ分かっていません(調べきれていないのですが、Hatchは常にeditableでインストールするようでした)。
そんなわけでスクリプト以外のケースは、しっくり来るツールを探し中です8


  1. 旭川で発表した内容です
  2. レポート
  3. Python処理系はサードパーティライブラリの配置ディレクトリ(site-packages)を1箇所しか持ちません。同じライブラリのバージョン違いを共存させるために、プロジェクトごとのsite-packagesを作ります9。これが仮想環境です
  4. Django用語のapplication単位ではインストールできるようです。docs.djangoproject.com 本エントリで言う「Djangoを使ったアプリケーション」は、Django用語のprojectとapplication両方を指しており、この単位ではやはりインストールしないかなと思います
  5. Pythonパッケージング用語集の気持ちとしては、pyproject.tomlを置いたら配布できるということなのでプロジェクトと呼ぶ、ということなのかもしれません(この気持ちを言い換えると、pyproject.tomlを置いていないならば、プロジェクトではない)
  6. このように考えるきっかけはこのトーク
  7. uv 0.3.0〜 uv run <script>
  8. 先日出た uv 0.4.0 が候補になるかも(宿題事項)
  9. 仮想環境しか手段がないわけではなく、Dev container(開発環境としてDockerコンテナを立て、そこにプロジェクトの依存をインストール)もあると思います。このエントリではあくまで主観で見かけることの多い仮想環境に振りました