はじめに
環境構築から始まって、変数・型・コレクション・関数・クラス・例外処理・ファイル操作・テスト・型ヒント・pandas・NumPy・matplotlib・FastAPI・Pydantic・非同期処理・環境変数管理・Docker化まで一通り触った。
振り返り記事として、率直な感想をまとめておく。「PHPエンジニアがPythonに移行するとどうなるか」の一例として参考になれば。
しんどかった部分
非同期処理の概念
一番時間がかかった。
PHPはリクエストごとにプロセスを立ち上げる同期モデルが前提なので、event loopという概念がそもそもなかった。JavaScriptのasync/awaitと同じだろうと思っていたが、Pythonのasyncioは「明示的にevent loopを起動する」という設計で、コルーチンの伝播(いわゆるasync汚染)も含めて理解するまで詰まった。
FastAPIを使うだけならasync defとawaitを書けば動くが、「なぜ動くのか」を理解するのに一番時間がかかった。
venvと依存管理
環境構築の記事でも書いたが、pip installがグローバルに入ってしまう問題、venvの有効化を忘れる問題、pyenvとvenvの使い分けが最初は混乱した。
PHPはcomposerが最初からプロジェクトローカルにインストールするので、この問題が存在しなかった。Pythonの依存管理はまだpip + venv + requirements.txtかPoetryかuvか、正解が一本化されていない印象がある。
インデントエラー
つまらないことだが最初の数週間はインデントミスによるIndentationErrorに悩まされた。PHPは{}で囲むのでインデントは整形の問題でしかないが、Pythonはインデントが構文の一部なのでズレるとすぐエラーになる。Ruffを入れてから解消した。
selfを毎回書くこと
慣れるまでは「毎回selfを引数に書くのは冗長では」と感じた。PHPの$thisは暗黙的に存在するので、明示的に書く設計に違和感があった。今は「メソッドも関数の一種でインスタンスを引数として受け取っている」という設計思想として納得している。
逆に楽だった部分
型ヒントの書き方
PHPのPHPDocコメントと型宣言が分離していた部分が、Pythonは引数と戻り値に直接書けてすっきりしている。
def process(items: list[str], max_count: int = 100) -> tuple[list[str], int]:
...
PHP 8以降はかなり改善されたが、Union型などPythonのほうが書き方が自然に感じる部分がある。
内包表記
最初は読めなかったが慣れると手放せない。array_map(array_filter(...))のネストがなくなって、コードの見通しが良くなった。
result = [x * 2 for x in nums if x % 2 == 0]
デコレータ
PHPにない概念だったが、理解してからはロギング・リトライ・キャッシュなど横断的関心事の分離がきれいに書けるようになった。@lru_cacheや@dataclassは特に便利。
pandasの集計能力
SQLで書いていたような集計がpandasで完結できるようになった瞬間は「これがやりたかったやつだ」となった。特にpivot_table()はSQLで書くとCASE WHEN地獄になるクロス集計が一発で書けて感動した。
FastAPIの自動ドキュメント生成
型ヒントを書くだけでSwagger UIが自動生成される。Laravelで別途Swaggerを設定していた手間がなくなった。「型を書けば書くほど得をする」という設計思想が一貫していて気持ちいい。
withステートメント
PHPのfopen/fclose地獄がwithブロックで解消される。ファイルだけでなくDBセッション・ロック・タイマーなどあらゆるリソース管理に使えるので、書くコードがシンプルになった。
PHPのほうが良いと感じた部分
依存管理の標準化
composerは「これ一択」という状況が長く続いていて、エコシステムが安定している。Pythonはpip/Poetry/uv/Pipenvと選択肢が多く、プロジェクトによって使っているツールが違うのは混乱しやすい。
ただし最近はuvが速さと使いやすさで注目されていて、今後収束していくかもしれない。
アクセス修飾子
public/protected/privateが言語レベルで強制されるPHPのほうが、チームで書くときの安心感がある。Pythonの命名規則による慣習(_/__)は「守ってほしいお願い」にとどまるので、型チェッカーやlinterに頼る部分が増える。
エラーメッセージ
これは主観だが、PHPのエラーメッセージのほうが親切な場合がある。Pythonのエラーはスタックトレースが深くなりがちで、最初は原因にたどり着くまで時間がかかった。慣れると読めるようになったが。
Pythonで好きになった書き方
半年書いてきて、「これはPythonらしくて好き」と感じるパターンをまとめた。
アンパック代入
first, *rest = [1, 2, 3, 4, 5]
print(first) # 1
print(rest) # [2, 3, 4, 5]
a, b = b, a # 変数のスワップ
f-string
name = "田中"
score = 95.678
print(f"{name}さんのスコアは{score:.1f}点です")
# 田中さんのスコアは95.7点です
PHPの"こんにちは、{$name}さん"より書式指定がスマート。
キーワード引数
send_email(
to="tanaka@example.com",
subject="テスト",
body="本文",
html=True,
)
引数名を明示することで、引数の多い関数呼び出しが読みやすくなる。PHPが欲しかった機能の一つ。
dataclass
@dataclass
class Point:
x: float
y: float
PHPでDTOを作るたびに__constructとプロパティ宣言を書いていたのが、これだけで済む。
for-else
for item in items:
if item == target:
print("見つかった")
break
else:
print("見つからなかった")
フラグ変数が不要になる。最初は「forにelseってなに」と思ったが、今は積極的に使っている。
今後の方針
この半年でPythonの基礎とデータ処理・API開発の基本は習得できた。
今後やっていきたいことを整理した。
深めたいこと
- SQLAlchemy(ORM)— FastAPIとDBを繋ぐ部分をまだちゃんとやれていない
- 非同期処理 — asyncioの深い部分。
asyncio.Queueやasyncio.Lockなど並行制御の仕組み - テストの品質 — pytestのfixture設計とカバレッジ向上
新しく触りたいこと
- scikit-learn — データ処理案件で機械学習が必要になりそうなので基礎だけでも
- Alembic — DBマイグレーション管理。LaravelのMigrationに相当
- Celery / Redis — バックグラウンドジョブ。LaravelのQueueに相当
PHPと並行して使っていく
PHPをやめるつもりはない。フロントエンドと密結合したWebアプリはLaravelが速いし、慣れているので生産性が高い。PythonはデータパイプラインとAPI開発で使い、PHPとPythonを案件に応じて使い分けていく方針。
PHPエンジニアがPythonを始めるときのアドバイス
同じ状況の人に向けて、やってよかったことをまとめた。
最初にやること
- pyenvとvenvを理解してから始める。依存管理の仕組みを把握してないと後で詰まる
- エディタはVS Code + Ruff + Pylanceを入れる。インデントエラーとリントが自動で解決される
PHPの知識を活かせる部分
- クラス・継承・インターフェースの概念はそのまま使える
- HTTPリクエスト・レスポンスの扱い方はFastAPIでもLaravelと似ている
- テストの設計思想(ユニット・インテグレーション・モック)は同じ
ハマりやすいポイント
- デフォルト引数にリストや辞書を使わない(ミュータブルの罠)
-
True/False/Noneは大文字始まり -
importのパスはファイル名と被らせない - 非同期は「なんとなく動く」ではなくevent loopから理解する
まとめ
PHPからPythonへの移行は、思ったより敷居が高くなかった。
動的型付け・オブジェクト指向・例外処理・テストの書き方など、PHPで身につけた概念がそのまま活きる部分が多い。型ヒントやデコレータ・内包表記など「PHPにないPythonらしい書き方」は最初こそ違和感があったが、慣れると手放せなくなった。
一番の違いは「データ処理の語彙の豊富さ」だと思う。pandasやNumPy・matplotlibのエコシステムはPHPには代替がない。データを扱う案件ならPythonを選ぶ明確な理由になる。