世界を動かす技術を、日本語で。

Pythonに切り替えて、実際に楽しんでいます

概要

  • Python を本格的に使い始めた理由と、その魅力の再発見。
  • AI開発 や「現場投入」レベルのPythonアプリ構築で感じたギャップ。
  • プロジェクト構成 や推奨ツール・ライブラリの紹介。
  • 実践的な設定例 やワークフローの共有。
  • 個人の経験に基づく 強い主観を含む内容。

Pythonを本気で使い始めた理由と進化の実感

  • AIブーム による巨大なビジネスチャンスの到来。
  • AI分野のデファクト言語 としてのPythonの地位。
  • 以前は 小規模なスクリプト作成 用途が主だったが、AIアプリ開発を機に本格利用。
  • VSCodeとの親和性 や、Unix系OSへの標準搭載による利便性。
  • Pythonエコシステムの進化 (ライブラリ・ツールの充実、速度向上、モダンな文法)。
    • 例:Cythonによる高速化、__init__などのレガシー要素の隠蔽。

プロダクション用途とスクリプト用途のギャップ

  • Jupyter Notebookや簡易スクリプト本番運用アプリ の間に大きな差。
  • 本番向け開発 に必要なツール・構成・ワークフローの重要性。

プロジェクト構成の好みと理由

  • モノレポ (フロントエンド+バックエンドを単一リポジトリで管理)推奨。
    • 複数リポジトリは検索性や管理性が悪化。
    • 一人開発なら分割は不要、シンプルさ重視。
  • プロジェクト自動生成ツール の理想像を模索中(CCDSはDS向けでフルスタックにはやや不向き)。
  • 典型的なプロジェクト構成例:
    • .github/:GitHub ActionsやDependabot設定
    • .vscode/:VSCode用設定
    • docs/:ドキュメント(MkDocs利用)
    • project-api/:バックエンドAPI(FastAPI等)
    • data/:データセットや静的ファイル
    • notebooks/:Jupyterノートブック
    • tools/:開発・デプロイ用スクリプト
    • src/app/:アプリ本体
    • src/tests/:テストコード
    • project-ui/:フロントエンド(Next.js, React等)
    • 各種設定ファイル(Dockerfile, Makefile, pyproject.toml, .gitignore, .pre-commit-config.yaml など)
  • 命名規則 は短く・ハイフン区切り、snake_caseは避ける。
  • フロントエンドとバックエンドは責務分離、重い処理はAPIサーバー側へ。

Pythonツールボックス

  • uv :高速なパッケージ管理&ビルドツール
    • 依存関係管理・仮想環境作成・インストール・ビルドを一元化
    • 主要コマンド例:uv init, uv add, uv sync, uv venv activate
    • 重要ファイル:pyproject.toml
  • ruff :超高速リンター&フォーマッター
    • isort, flake8, autoflakeなどを統合
    • PEP8準拠
  • ty :静的型チェックツール
    • typingモジュールと組み合わせて型安全性向上
    • Astral製(uv, ruffも同社製)
  • pytest :標準的なテストフレームワーク
    • シンプルなテスト記述・豊富なプラグイン
    • テスト実行例:uv run pytest
  • Pydantic :データ検証&設定管理
    • 環境変数や.envから設定を自動読み込み・型検証
    • 例:BaseSettings継承クラスで設定管理
  • MkDocs :静的ドキュメントサイト生成
    • OSSプロジェクトのデザインを流用しやすい
  • FastAPI :高速API構築フレームワーク
    • Starlette, Pydanticベースでパフォーマンス・型安全性に優れる
  • dataclasses :データ格納用クラスの簡易定義
    • __init__や__repr__などの自動生成でボイラープレート削減

バージョン管理とCI/CD

  • GitHub Actions :CI/CDパイプライン自動化
    • OSごとのテスト・ビルドを簡単に設定
    • 例:Dockerコンテナ内でpytest実行
  • Dependabot :依存パッケージの自動アップデート
    • .github/dependabot.ymlで設定
  • Gitleaks :機密情報のコミット防止
    • APIキーやパスワード漏洩対策
  • pre-commit :コミット前フックで静的解析や整形を自動実行
    • ruffやgitleaksとの組み合わせ推奨

まとめとコメント募集

  • 紹介したツール・構成は筆者の主観が強い が、実際の開発で役立ったものばかり。
  • 他におすすめのツールや工夫があれば、ぜひコメントで共有してほしい

Hackerたちの意見

Pythonは、__init__や__new__などのレガシーな醜さをうまく隠して、良いセンスを持つ開発者に合わせて文法を柔らかくしている。__init__や__new__の何が問題なの? @dataclassはとても素敵な構文糖だけど、初期化子やアロケーター、コンストラクタのダンダーメソッドにアクセスできることが「レガシーな醜さ」だと主張しているの? これは、Pythonicなビルトインを意識したPythonの核心だよ。奇妙だね。

奇妙なのは、それを醜いと考えないことだね。Kotlin: コンストラクタはクラス定義の一部か、キーワードのコンストラクタ。Ruby: initialize JS: constructor Python: new, init まさにこのミームだよ: https://knowyourmeme.com/memes/three-headed-dragon

おそらく、普通の識別子に特別な意味を持たせるシステムのことだね。__はPythonの予約語でもなんでもない。でも、メソッドや属性の名前を付けるときに従うべき一連の慣習があって、それが明らかに人工的なんだ。言語定義の特別な部分を言語構文の特別な部分にする方が、他の似ていないものと区別なく扱うよりもクリーンだと思う。C++では、クラスにバイナリの+演算子を定義したい場合、特別な名前operator+を持つメソッドを与える。Pythonでは、同じことをするために、擬似特別名__add__を持つメソッドを与える。Pythonのやり方が悪いとは思わない?

__init__や__new__の何が問題なの? @dataclassはとても素敵な構文糖だけど、初期化子やアロケーター、コンストラクタのダンダーメソッドにアクセスできることが「レガシーな醜さ」だと主張しているの? 私の読みでは、「醜さ」はメソッド名、特にダブルアンダースコアにあって、メソッド自体の可用性ではないと思った。

もう10年くらいプロでPythonやってるけど(バックエンドのウェブ開発やファイル処理)、著者がダンダーメソッドを「レガシー」と表現したのはあまり好きじゃないな。でも、C#のバックグラウンドからすると、あんまり使うことはないんだよね。著者はJavaについてのブログも書いてるけど、C#とそんなに違わないから、もしかしたらそのせいかも。コードの「大局」を考えるようになれば、ダンダーも取り入れるようになるかもしれないけど、それまでは…

誰かがPythonを好きになれることを発見してくれて嬉しいよ。プロジェクトのためにRubyを提案してたのに、顧客がPythonを強く希望したから、仕方なく学ぶことになったんだ。何年も前の話で、その頃はRubyがずっと遅かった。イライラしたけど、慣れて、今では楽しんでるよ。だけど、Makeの説明と使い方には問題があると思う!:-D 依存関係を使わないなら、何のためにあるの?ケース文でスクリプトを書いた方がマシだよ……真剣に言ってるわけじゃないけど、今の若者がMakeを理解できないのは、文化の悲しい反映だと思う……それと、私の庭から出て行ってくれ、いい? :-)

ケースステートメントを使ったスクリプトを書いた方がいいかも… 最初はこれで始めて、シンプルなフラットMakefileに進化した。 基本的には同じだけど、Makeの方が標準的に感じるから(ここにMakefileがあるのに対して、ここにランダムなbashスクリプトがある)。

文法が人間に優しいだけでなく、PythonインタープリターがすべてのUnixディストリビューションにネイティブに統合されているからだ。これはかなり楽観的な評価だね。「import json」以上のことをしようとすると、仮想環境の深淵に引き込まれる可能性が高い。たとえば、Python 3.13.xで作成したものをUbuntu 22.04や24.04(LTS)/ Rocky 9で動かすと、いろいろな問題が出てくる。仮想環境やコンテナ(Dockerのような)/バージョン管理ツールがすぐに必須になるよ。

これはuvで解決されるよ。

“import json”は、バッテリーが含まれていない言語でライブラリを選んでインストールする必要があるようなことだし、標準ライブラリに含まれている多くのモジュールの一つに過ぎない。それは大規模なプロジェクトのための説得力のある基盤ではないけど、これまでに標準ライブラリだけで済んだ便利なプロダクションコードをたくさん出荷してきたから、デプロイやセキュリティパッチについて考える時間は全くなかった。あと、もう2000年代じゃないからね。アプリケーションのインストールを隔離するためにvenvを使うのは、もうそんなに難しくないし、長い間 decentなパッケージマネージャーもあったよ。

ちょっとバカげた理論なんだけど、docker/コンテナがこんなに早く普及したのは、ひどいPythonの依存関係地獄をうまく解決したからだと思ってる。 何かが悪いときは、豪華なchrootが動くものを出荷する唯一のエルゴノミックな方法になってる。 自分がPythonに触れたのは、2012年頃にサーバーにPythonで書かれたサービスをインストールしたとき。 依存関係地獄や、クソみたいなvenvコマンド、ウェブサーバーを動かすためにこんなに苦労するなんて、本当に大変だった。 それ以来、Pythonは10年以上も避けてた。 ほとんど見るたびに、興味がなくてその場を離れてた。 たまに使ったときは、またそのクソの山に戻って、なぜ普段避けてるのか思い出してた。 macOSのbrewの扱い方もすごくイライラする。 基本的なpip installコマンドを壊したり、ライブラリをコマンドとしてインストールするけど、他のPythonスクリプトで使えないようにするなんて、なんてクソな災害なんだ。 本当に何を話してるのか分からないけど、初心者としては、これが本当に愚かで混乱させられるから、もっと生産的で楽しい作業に移ってる。 「Pythonがちゃんとしたらまた考える」って心の中でメモしてる。 でも、uvは、少なくとも自分の初心者で皮肉な目には、ほとんどのクソを取り除いてくれた。 少なくとも表面的には、Pythonで始めた小さなおもちゃプロジェクトでは、ほとんどのひどいクソを取り除いてくれた。 uv inituv adduv run。 そして、ちゃんと動くんだ。

いつでも仮想環境を使うべきだよ。 一つのディレクトリだし、どうしてそれが深淵なの? 今はpipが、パッケージをシステム全体にインストールしようとすると文句を言うよ。

そう、仮想環境やコンテナを使った方がいいよ。重すぎて管理が大変に見えるかもしれないけど、ライブラリのアップグレードでPythonのコードが壊れるのが怖くてシステムをアップデートできない状況にはなりたくないからね。

いや、全然。自分で「難しくしてる」レベルにどうやって到達するのか分からないよ。特定のバージョンのPythonを使いたいけど、Ubuntuにはない場合、こうするんだ。1. ビルド依存関係をインストールする https://devguide.python.org/getting-started/setup-building/#... 2. 欲しいPythonのソースバージョンをダウンロードする https://www.python.org/downloads/source/. tarで解凍する 3. ./configure --enable-optimizations --with-lto を実行 4. make -s -j [コア数] を実行 5. sudo make altinstall これで特定のバージョンがインストールされて、デフォルトのシステムPythonは上書きされないよ。その後、pipをpython3.xx -m pipにエイリアスして、正しいものが実行されるようにするんだ。すべてのライブラリやpip installの実行可能ファイルは、特定のPythonバージョンの下で~/.localフォルダにローカルインストールされるよ。別のツール(例えばnode)を使って異なるバージョンを管理したい場合は、asdfを使うといいよ。フォルダごとにバージョンを選べるからね。仮想環境は、特定のバージョンでテストしたい本番コードには本当に役立つけど、それ以外ではあまり使わないかな。

リンク先のスクリプトのコードについてちょっとしたメモ。 API_KEY = os.environ.get("YOUTUBE_API_KEY") CHANNEL_ID = os.environ.get("YOUTUBE_CHANNEL_ID") もしAPI_KEYかCHANNEL_IDがなかったら、 print("YOUTUBE_API_KEYかYOUTUBE_CHANNEL_IDが欠けています。") exit(1) 「XかYが欠けています」って表示されると、理由もないのにORが入ってるからユーザーはすごくイライラするよね。 if not API_KEY: print("YOUTUBE_API_KEYが欠けています。") exit(1) if not CHANNEL_ID: print("YOUTUBE_CHANNEL_IDが欠けています。") exit(1) こっちの方がユーザー体験はずっと良いし、開発時間も0.00001%遅くなるだけ。

ブールフラグを追加して、最後に一つのexit(1)を使うのはどう? そうすれば、ユーザーは設定されていない環境変数を全部確認できるよ。

これは細かいことだけど、:=演算子を使うのはいい使い方だと思う。 if not (API_KEY := os.getenv("API_KEY")): ... 内部ツールでは、os.environ["API_KEY"]がKeyErrorを発生させるのをそのままにしてる。 それで十分説明的だよ。

さらに良いのは、すべての環境変数を取得して、欠けているものを報告すること。

両方やった方がいいと思う:詳細な文字列を出力して、どちらかが出力されたら終了する。

さらに良いのは、すべての条件をチェックして、すべてのエラーを報告すること。最初の変数を追加して、もう一度実行して別のエラーが出るのは勘弁してほしいな。時々それは避けられないけど、そうじゃない時はちょっと煩わしいよね。

期待される環境変数を文書化するためのargparseみたいなものがないのは驚きだわ。

環境からチャンネルIDみたいな一時的な引数を取るのは、可視性やユーザーの快適さに対してもっと攻撃的だよね。

こういう決定をする時は、ユースケースや対象者が重要だと思う。この場合、ユーザーはコンソールで実行してるPythonスクリプトとやり取りしてる人だと思う(おそらくprintで)。だから、両方の設定がされてるか確認するだろうし、あんまり気にしなくてもいいと思う。環境変数の設定についてドキュメントを渡すべき?それを実行してるOSに合わせてカスタマイズするべき?とかね。もしユーザーが典型的な消費者で、典型的なインターフェースを使ってるなら、もう少し手助けしてあげた方がいいね。

「AIの事実上のプログラミング言語は何か知ってる?そう、あのこっそりしたやつ。」って、これってPyTorchのこと? もし違ったら、著者が何を考えてるか予想できる? 「構文が人間に優しいだけでなく、PythonインタプリタがすべてのUnixディストリビューションにネイティブに統合されているから。」って、これはGNU/Linuxのこと? UNIX(UNIX系)はLinuxだけじゃなくて、いくつかのUNIXディストリビューションには基本システムにPythonが含まれていないから、ユーザーがインストールするかどうか選べるんだよね。 自分はそういうディストリビューションを使ってるから、特にソフトウェアが必要じゃなければPythonはインストールしない。 そういう場合、そのソフトウェアを使い終わったらアンインストールしてる。 例えば、YouTubeチャンネルのメタデータを取得するのにPythonは使わないで、19行のシェルスクリプト(ashじゃなくてbash)を使ってる。 起動時間が速いし、Pythonとは違って、使ってるUNIXディストリビューション(LinuxとBSD両方)には基本システムに含まれてる。 でも、もしyt-dlpを使って何かテストする必要があれば、一時的にPythonをインストールするかも。

  1. Pythonをソースからコンパイルするんだけど、プロジェクトの面倒な点は、起動時間が遅いのに加えて、Makefileにアンインストールターゲットが含まれていないこと。

「で、AIの実質的なプログラミング言語って何だと思う?そう、そのずる賢いやつさ。」彼は一般的にPythonのことを言ってるんだ。「文法が人間に優しいだけじゃなくて、PythonのインタープリタがすべてのUnixディストリビューションにネイティブで統合されてるからね。」彼が言いたいのは、UbuntuやFedora、NixOSみたいな主要なLinuxディストリビューションで簡単に使えるってことだと思う。ネイティブって言葉はちょっと違う気がするけど、私もbash使ってるけどPythonはすごいよね。確かにパッケージや速度に関する問題はあるけど、それでも仕事に適したツールであることが多い。強力で、使いやすくて、オープンソースだし。

なんでPythonをそのまま放置しない方がいいの?セキュリティ?

ちょっと気になるんだけど、DataclassとPydanticのBasemodelを使う理由は何?もしPyDanticの依存関係がなかったらDataclassを使いたいと思うかもしれないけど、あるならどこでも使えばいいじゃん。

質問に答えるために、attrsプロジェクトからの詳細な比較を紹介するね: https://www.attrs.org/en/stable/why.html ちょっとバイアスの可能性はあるけど、ほとんどの主張はよく考えられてると思ったよ。追記:役に立ちそうな別の情報も見つけたよ: https://threeofwands.com/why-i-use-attrs-instead-of-pydantic...

構築時のデータ検証によるパフォーマンスの低下。msgspecが好きなんだけど、こっちの方がずっと軽くて速いよ。

主な理由は(以前は)パフォーマンスだったけど、pydantic 2.0以降はもう問題じゃないから、今は何でもpydanticを使うようにしてる。

バリデーションやシリアライズが必要なければ、余計な荷物だよね。僕の目安は、シリアライズが必要な時はPydanticを使う、それ以外はデータクラスを使うって感じ。

チャドな答えはpydantic.dataclassを使うことだね。

僕の目安は、データクラスはコンパイル時の型チェック用、pydanticクラスはランタイムの型チェック用って感じ。

プロジェクトの構造を自動生成してくれるツールが欲しいんだけど、まだ自分に合うのは見つけてないんだ。これにはcookiecutterをおすすめするよ。自分がよく使うテンプレートがいくつかあるんだ:python-lib: https://github.com/simonw/python-lib click-app: https://github.com/simonw/click-app datasette-plugin: https://github.com/simonw/datasette-plugin llm-plugin: https://github.com/simonw/llm-plugin これをこんな感じで実行できるよ:uvx cookiecutter gh:simonw/python-lib

Copierが今のホットなやつだよ! https://copier.readthedocs.io/en/stable/

僕の考えは(Rubyを使って)https://github.com/coezbek/baker これ、テンプレートリポジトリをコピーするんじゃなくて、実行すべき手順のリストを作るんだ。手順は手動(APIキーを取得してここに保存する)と自動('uv init'を実行する)の両方があるよ。Markdown構文、Rubyの文字列補間、bashを使ってる。ymlベースの設定が大嫌いで生まれたものなんだ。

ほぼ同じパターンでプロジェクトを作ってるんだ。ちょっと不気味だね。Python開発者のエコシステムの人たちが、ほとんどのことをかなり均一なやり方でやるようになってるのかな?自分の選択肢が「自分だけのもの」だと思ってたけど、こんなに一貫性があると、自分の自由意志を疑っちゃうよ。赤ちゃんに「ユニーク」な名前をつけようとして、みんなとほぼ同じ名前を選ぶような感じだね。自分がユニークだと思ってた名前が、実は2番目に人気の名前だったりする。

まるで、あらゆるスペクトルの下層のパイロット波が人間のエゴを構成する粒子として保持しているかのように - 存在すること、笑

この手のアーキテクチャは、少なくとも10年くらい前からPythonで人気だけど、あなたの言う通りだと思う。構造が理にかなってるから、合理的なエンジニアがみんな使うようになるんだよね。

Pythonって、冗長でありながら足りない部分もあるのは僕だけかな?簡単に何かをするために500個の依存関係が必要だったり、つまらないことをするのに数十行(下手したら何百行)も必要だったりする。Pythonを書くのは避けてる、余計なことが多すぎるから。Perlの方が好き、実際にすぐに物事が進むから。Pythonはプログラミングのためのプログラミングって感じがする。

うわ、バックエンドが2007年の古いコメントを漏らしてるじゃん。

Perlが使いやすくてパワフルな例を教えてもらえる?

人それぞれだけど、私の経験では、Pythonの主な使用ケースは依存関係が少なくて済むことが多いかな。多くの簡単なタスクはすでに言語に組み込まれてるし。Pythonが完璧だとは言わないけど、その点では確かに優れてると思う。逆のケースを見つけたのはどんな使い方だったのか、ちょっと気になるな。Python対Perlの古典的な議論は、結局は自分が一番快適に感じるものを使うことに尽きると思う。人それぞれだし、それは全然問題ないよね。

こういうのを書こうと思ってたんだけど、「どれだけシンプルにできるか」って視点で探ってみたいな。俺の世界はKubernetesが多いけど(シチュエーションによっては最高なんだけど)、ソロ開発のための迅速なイテレーション用に設計されたスタックから複雑さを削ぎ落とせるかな。例えば、以下のように:

「プロジェクトのUIで重いデータ処理を行わないことが重要です… ブラウザアプリケーションを軽く保ちながら、重い処理やビジネスロジックをサーバーに委譲します。」 複雑さを減らして、バックエンドから直接HTMLを提供する。 ありがとう、tyがどこに行くのか気になるけど、ミニマムの複雑さのスタックでは、リリース前のツールに複雑さトークンを使えない。 pydantic…データクラス。どちらか一方だし、ずっと混乱しちゃう。post_init(データクラス)なのか、それともpost_model_init(pydantic)なのか、確認しなきゃいけなかった! docker。もし既にuvがあるなら、dockerなしでやっていける?uv syncは、正しい設定であれば、ほぼ静的にコンパイルされたバイナリに近い体験を提供できる。ボリュームなどは扱えないから、dockerの機能を使ってるなら、この考え方は通用しない。でも、dockerにこだわらないなら、開発と本番でuvだけでやっていける?エンタープライズでは多分無理だし、本番で依存関係をダウンロードできるとは思えないけど、ソロでやるなら… compose。フロントエンド、バックエンド、そしておそらくデータベースがある。バックエンドを管理するのにuvだけでやって、ローカルのsqlite dbで済ませられるかな?つまり、複雑さを減らしつつ、迅速なイテレーションが可能で、すべての機能が揃っていて、自分で全部作らなくてもいいスタックはこんな感じになるかも:

  • uv
  • fastapi + jinja + htmx + surreal + picocss
  • sqlite