Go の構文はすべて、半日もあれば読み終えられます。すでに Python を書いているなら、その大半は見覚えがあるはずです。ただ、その見覚えは当てになりません。新しいキーワードはすぐに覚えられます。Go への移行で難しいのは、Go がサポートしていないいくつかの Python の習慣を捨てることです。Go には捕捉すべき例外も、継承すべきクラスも、リスト内包表記も、気軽に入り込めるインタプリタもありません。その代わりに手に入るのは、明示的なエラー値、struct と interface、goroutine(軽量スレッド)、そしてコードを動かす前から文句を言ってくるコンパイラです。この記事では、Go での最初の 1 か月が安堵になるか苦闘になるかを左右する考え方の転換を取り上げます。
要約
- Go 開発者は Go に満足しています。回答者の 91% が Go に満足していると答え、約 3 分の 2 が「非常に満足」でした。Google の公式調査の中で最も高い結果です(Go Developer Survey 2025)。
- Go で一番大きな変化の根底にある考え方は、すでに使っているはずです。Python 開発者の 88% が型ヒントを「常に」または「頻繁に」使っていると答えています。つまり静的型付けは、すでに身につけ始めている習慣です(Typed Python 2024 Survey, Meta)。
- 移行したチームは実際に成果を上げています。Khan Academy が Python のバックエンドを Go で書き直したところ、レンダリングに約 28 秒かかっていたページが約 4 秒になりました(Khan Academy Engineering)。Reddit はコメントサービスを Go に移行し、p99 の書き込みレイテンシを半減させました(InfoQ)。
- Python のほうが規模は大きく、それで問題ありません。プロの開発者のうち Python を使っているのは 54.8%、Go は 17.4% で、データや AI の分野では Python が圧倒的です(Stack Overflow 2025)。Go が競うのはもっと限られた領域で、レイテンシが重要なバックエンド、API、CLI です。
目次
- Python 開発者は Go を学ぶべきか?
- チームが Python から Go に移行する理由
- 静的型付け:すでに半分は習得済み
- エラーは例外ではなく値
- 並行処理:goroutine vs GIL
- クラスと継承の代わりに struct と interface を使う
- マジックは少なく、明示的に
- Python から Go へのチートシート
- ツール:バイナリはひとつ、フォーマッタもひとつ、テストは組み込み
- Python から移って恋しくなるもの
- 移行の進め方
- よくある質問
- 今日から Go を書き始めましょう
Python 開発者は Go を学ぶべきか?
はい。特に、仕事の中心がバックエンドサービス、API、インフラ、コマンドラインツールへ移りつつあるなら学ぶべきです。Google の公式調査では、Go 開発者の 91% が満足しており、3 分の 2 近くが「非常に満足」と答えました。主要な言語の中で最も高い満足度です(Go Developer Survey 2025)。この満足度は、Go の巧妙さよりも、挙動の予測しやすさから来ています。そして予測しやすさこそ、コードベースが数千行を超えたころに多くの Python 開発者が欲しくなるものです。
移行はすぐに進みます。そのまま活かせる知識が多いからです。関数、slice、map で考えることにはすでに慣れていますし、作業をパッケージに分けてテストを書くことも普段からしているはずです。問題への取り組み方は変わりません。変わるのは、自分で決めたことを言語がどれだけ厳格に守らせるかという点です。Go は Python の柔軟性をいくらか手放す代わりに保証を得ています。この記事の大半は、それがどこに現れるかについての話です。
チームが Python から Go に移行する理由
チームが移行する理由はたいてい同じです。すぐに書けた Python のサービスが、動かすには遅すぎる、あるいはコストがかかりすぎるようになったのです。Khan Academy がサーバーを Go で書き直したとき、1,000 人の生徒がいるクラス名簿の読み込みは Python で約 28 秒かかっていましたが、約 4 秒で表示されるようになりました。7 倍近い改善です。データストアの競合警告も、1 時間あたり約 100 件からほぼゼロに減りました(Khan Academy Engineering)。
Reddit でも似たような結果が出ました。2025 年にコメントツリーのバックエンドを Go のマイクロサービスへ移行したところ、p99 の書き込みレイテンシは従来の Python システムの半分になりました。従来のシステムでは、ときに 15 秒まで跳ね上がることもありました(InfoQ)。
最近の例で特に目を引くのが、AI アプリビルダーの Lovable です。バックエンド全体、42,000 行のコードを Python から Go へ書き直しました。サーバーインスタンスは 200 台から 10 台に、デプロイ時間は 15 分から 3 分に減り、平均リクエスト時間は 12% 速くなりました(Lovable Engineering)。書き直しのきっかけは並行処理でした。Lovable では、チャットのリクエスト 1 件が 50 回以上の HTTP 呼び出しに分岐することがあります。Go はこの種の並列ワークロードをネイティブに扱えますが、Python の GIL では扱いにくくなります。
どの事例でも、コンパイルされ、静的型付けで、ガベージコレクションを備えた Go のランタイムは、1 台のサーバーでより多くの仕事をこなします。そのため同じトラフィックでもコストが下がり、負荷がかかっても挙動が安定します。
静的型付け:すでに半分は習得済み
Python 開発者は Go の中でも特に静的型付けを恐れがちですが、実は一番早く慣れるのもこれです。多くの人がすでに自分から取り入れているからです。2024 年の調査では、Python 開発者の 88% が型ヒントを「常に」または「頻繁に」使っていると答え、よく使われるツールは mypy と Pydantic でした(Typed Python 2024 Survey, Meta)。関数シグネチャに型注釈を付け、CI で型チェッカーを走らせているなら、Go の根本的な前提はすでに受け入れています。Go はそのチェックを必須にし、任意のツールではなくコンパイラの中に置いています。
実務上の違いは、間違いに気づくタイミングです。Python では、型の不一致は実行時に表に出ます。本番環境で見つかることも多く、デプロイから何時間も経ってからのこともあります。Go では、同じミスでビルドが止まります。int が期待される場所に文字列を渡すことはできませんし、未使用の変数を残すこともできません。そのため、代入したままチェックしていない err があるとコンパイルが通りません。初心者には小言のように感じられるでしょう。午前 2 時に NoneType has no attribute エラーをデバッグした経験があれば、むしろ安全網のように感じられるはずです。
具体的には次のようになります。Go 版は、Total が誤った型になる場合にはコンパイルが通りません。Python 版なら、呼び出し側が数値を渡してくれることをただ期待するだけです。
example.gogotype Order struct { ID string Total int // cents, never a float, never a string } func discount(o Order, pct int) int { return o.Total - (o.Total * pct / 100) }
型推論のおかげで、コードが冗長になることはありません。:= を使えば Go が値から型を判断してくれるので、あちこちで int と書く代わりに count := 0 と書けます。宣言による安全性はそのままに、Python の簡潔さの大部分も残せます。
エラーは例外ではなく値
これが最も大きな適応ポイントで、1 週間ほどは違和感があるでしょう。Go には try も except もなく、Python でいう意味での例外もありません。失敗する可能性のある関数は最後の戻り値として error を返し、呼び出したその場でチェックします。スタックを遡って投げられ、どこか遠くで捕捉されるものは何もありません。エラーが起きたその行で、処理するか、無視するか、呼び出し元へ渡すかを決めます。
このイディオムは何千回も打つことになります。
example.gogoresp, err := http.Get(url) if err != nil { return fmt.Errorf("fetch %s: %w", url, err) } defer resp.Body.Close()
Python 開発者は最初、if err != nil を嫌うことがよくあります。ブロック全体を 1 つの try で囲むのに比べると、呼び出しのたびに 3 行のエラー処理が続くのは冗長に見えるからです。ただ、この繰り返しは意図的なものです。関数を上から下へ読むだけで、すべての失敗経路が見えます。離れたハンドラーへの見えないジャンプはありません。%w 書式指定子は元のエラーをラップするので、呼び出し側は引き続きそれを調べられます。これが Go 版の例外チェーンです。
この習慣は Python にも持ち帰れます。呼び出し箇所で失敗を処理することに慣れると、広範な except Exception ブロックの正体が見えてきます。何が起きたのかという情報を失うための手段です。
並行処理:goroutine vs GIL
並行処理は、Go が「型付きの Python」ではなくなり、別の道具になるところです。CPython の Global Interpreter Lock(GIL)は一度に 1 つのスレッドしか Python バイトコードを実行できないようにしているため、スレッドで CPU バウンドな処理を並列実行することはできません。GIL のないフリースレッド版のビルドは PEP 703 のもとで Python 3.13 に実験的に導入されましたが、デフォルトではなく、エコシステムの対応もまだ追いついていません(Python ドキュメント)。現時点では、CPU バウンドな Python をスケールさせるには通常は複数のプロセスを動かすことになり、それに伴うメモリと調整のコストも払うことになります。
Go は、最初から並行処理を中心に設計されています。goroutine は前に go を付けた関数呼び出しで、ランタイムは何千もの goroutine を CPU コア全体に振り分けます。邪魔をする GIL はありません。goroutine 同士は、共有メモリではなく channel でやり取りします。100 件のフェッチを並行して始めるのに必要なコードはこれだけです。
example.gogoresults := make(chan string) for _, url := range urls { go func() { resp, err := http.Get(url) if err != nil { results <- "error: " + url return } defer resp.Body.Close() results <- url + " ok" }() } for range urls { fmt.Println(<-results) }
asyncio を書いたことがあるなら、目指すところはすでに理解しているはずです。Go は、コードを async と同期の 2 色に塗り分けることなく、そこにたどり着きます。どんな関数でも goroutine の中で実行できます。await を書くことも、イベントループを起動することも、async 専用版のライブラリを探し回ることもありません。Go のサービスが負荷に強い大きな理由はここにあります。Go の並行処理モデルは後から追加されたものではなく、言語に組み込まれています。
クラスと継承の代わりに struct と interface を使う
Go にはクラスも継承もありません。これに驚く人は多いのですが、本来それほど驚くことではありません。データは struct でモデル化し、メソッドを紐づけて振る舞いを持たせます。self が暗黙に渡されることはなく、__init__ も、拡張すべき基底クラスもありません。Python ならクラス階層を使う場面で、Go はコンポジションを使います。親から継承するのではなく、ある struct を別の struct に埋め込んで、そのフィールドとメソッドを再利用します。
interface は Go のエレガントさが際立つ部分で、その仕組みは予想とは違います。型は、必要なメソッドを持っているだけで interface を満たします。implements キーワードも、登録の手順もありません。struct に Read([]byte) (int, error) メソッドがあれば、それは io.Reader です。Python でおなじみのダックタイピングが、コンパイル時にチェックされる形です。
example.gogotype Notifier interface { Notify(msg string) error } type SlackClient struct{ webhook string } func (s SlackClient) Notify(msg string) error { // any type with this method is a Notifier, automatically return post(s.webhook, msg) }
必要な考え方の転換は、「このオブジェクトは何か」から「このオブジェクトは何ができるか」への切り替えです。interface は予想よりも小さくなり、メソッドが 1 つだけということもよくあります。そして interface は、それを満たす型の隣ではなく、それを使うコードの隣で定義します。この逆転が自然に感じられるまでには数日かかります。慣れてしまえば、Python に戻ったときに最も恋しくなるものの 1 つになりがちです。
マジックは少なく、明示的に
Python は巧妙さに報いる言語です。デコレータ、メタクラス、ダンダーメソッド、モンキーパッチ、動的な属性アクセスを使えば、言語を好きなように曲げられます。Go は、そのほとんどを意図的に省いています。デコレータもメタクラスも演算子オーバーロードもなく、自分が所有していない型にメソッドを追加する方法もありません。どこか別の場所で起きていることを知らなくても、ある行が何をするのかはほぼ常にわかります。
初日は窮屈に感じますが、2 か月目には気が楽になります。見慣れない Go のコードベースを読むのは、ほとんどただ読むだけの作業です。裏で振る舞いを書き換える隠れた仕組みがないからです。欠点は、Go のほうが冗長になりがちなことです。Python なら 1 行の内包表記で済むところを、ループで書くこともあります。Go コミュニティは、それを妥当な代償と考えています。言語の設計者は、コードは書かれるよりもはるかに多く読まれると考え、読み手のために最適化しました。
Python から Go へのチートシート
日常的に使う Python の構文のほとんどには、Go に直接対応するものがあります。最初の 1 週間はこの表を開いておきましょう。名前が変わり、記号の使い方が厳しくなりますが、概念はほぼ 1 対 1 で対応します。
| Python | Go | 補足 |
|---|---|---|
x = 5 | x := 5 | := で型を推論 |
def f(a, b): | func f(a, b int) int { | 戻り値も含めて型を宣言 |
list | []T (slice) | 型は固定だが、append で list のように伸長 |
dict | map[K]V | キーと値にも型を指定 |
for x in items: | for _, x := range items { | range でインデックスと値を取得 |
try / except | if err != nil { | エラーは投げずに戻り値で返す |
class Foo: | type Foo struct { | これにメソッドと interface を組み合わせる |
None | nil | ポインタ、slice、map、interface で使用 |
f"{name}" | fmt.Sprintf("%s", name) | f-string はないので fmt パッケージを使用 |
pip install | go get | モジュールはツールチェーンに組み込み |
# comment | // comment | 考え方は同じで記号が違う |
見た目の変化で最も大きいのは、波かっこが使われることと、コロンがなくなることです。Go は静的型付けなので、書き換えが間違っていれば、その時点でコンパイラが指摘してくれます。これを活用しましょう。ビルドを失敗させてエラーを読むことが、対応関係を覚える一番の近道です。
ツール:バイナリはひとつ、フォーマッタもひとつ、テストは組み込み
Go のツールは、人々が Go を使い続ける理由の中でも、最も過小評価されているものの 1 つです。requirements.txt のずれも、有効化すべき仮想環境もなく、フォーマッタ、リンター、テストランナーを別々に組み合わせる必要もありません。go コマンドがそのすべてを担い、1 回のインストールで手に入ります。コンパイルすると、インタプリタも同梱すべき依存関係も不要な静的バイナリが 1 つできるので、デプロイはファイルを 1 つサーバーにコピーするだけで済むこともよくあります。
最初に気づくのは次の点です。
go buildでバイナリが 1 つできます。ターゲットマシンに Python をインストールする必要はなく、インタプリタをパッケージングすることもなく、デプロイ時に依存関係の問題が表に出ることもありません。gofmtがフォーマットをめぐる議論を終わらせます。Go には正規のスタイルが 1 つだけあり、それを強制するツールがあるので、コードレビューで空白について議論することはありません。blackが標準で組み込まれていて、全員が使っているようなものです。go testはツールチェーンに付属しています。テストはコードの隣の_test.goファイルに置き、コマンド 1 つで実行できます。pytestをインストールしたり設定したりする必要はありません。go vetとモジュールシステムは組み込みです。依存関係はgo.modでバージョン管理されてgo getで取得され、サードパーティのツールなしでビルドを再現できます。
何年も Python の環境管理に付き合ってきた身には、環境をまったく管理しなくてよいことが、毎日のちょっとした安心になります。コードを書き、go build を実行し、できたものをデプロイするだけです。
Python から移って恋しくなるもの
Go の厳格さには現実のコストがあるので、何を手放すのかは知っておくべきです。最も恋しくなるのは REPL でしょう。Go にはライブラリを試しに触ったりスニペットを確かめたりできる対話型インタプリタがないので、何かを試すには小さな main を書いて実行することになります。リスト内包表記や辞書内包表記も恋しくなるはずです。Go では毎回ループを書かなければなりません。そしてときには Python の柔軟性、つまり先に型を宣言しなくても、その場でデータの形を変えられる身軽さも恋しくなるでしょう。
より重要なのはエコシステムの差です。快適さだけでなく、キャリアにも関わるからです。データサイエンス、機械学習、科学技術計算は Python の独壇場です。それは Python 開発者の時間の使い方にも表れています。上位に並ぶのはデータ探索、Web 開発、ML です(JetBrains State of Python 2025)。モデルの学習やデータフレームの操作が仕事なら、その分野で Go が Python に取って代わることはありませんし、Go もそれを目指してはいません。乗り換えるより、Go を追加するほうが理にかなっています。データや AI の作業には Python を使い続け、高速で信頼性の高いサービス、CLI、インフラ用ツールが必要なときには Go を使いましょう。これは Go 開発者が実際に作っているものとも一致します。75% が API や RPC のサービスを、62% がコマンドラインツールを開発しています(Go Developer Survey 2024 H2)。
移行の進め方
Python 開発者が Go を最速で身につける方法は、違いについて読むのをやめ、実際のコードでその違いにぶつかることです。概念はすでに理解しています。必要なのは反復です。構文とエラー処理のリズムを意識しなくても書けるようになるまで、小さな採点付きの演習を十分にこなしましょう。例外から値としてのエラーへの転換は、実際のプログラムで if err != nil を数百回打って初めて定着します。
チュートリアルを受け身で眺めるのはやめましょう。他人が Go を書くのを見ても、自分で書く力はあまり身につきません。言語がこれほど簡単に見えると、なおさらそうしたくなります。毎日少しずつ Go を書き、間違えたらすぐに教えてくれるフィードバックを受けましょう。そして何も調べずに関数を書けるようになったら、すぐに実際に動くものを作りましょう。小さな JSON API、ファイルを整形し直す CLI、別のサービスを呼び出してレスポンスの形を変えるプログラムは、どれも Go なら短いプロジェクトで済みます。そして、仕事で頼りにすることになるパターンを使います。
よくある質問
Go は Python より習得が難しいですか?
構文は難しくありません。Go の予約語は 25 個しかなく、フォーマットのスタイルも強制される 1 つだけなので、覚えることは Python より少なくて済みます。難しいのは規律のほうです。エラーを値として扱い、型を宣言するには、最初により多くの手間がかかります。すでに型ヒントを使っている Python 開発者、つまり全体の 88% は、実際に一歩先を行っています(Typed Python 2024 Survey, Meta)。
なぜ Go は Python より並行処理が得意なのですか?
CPython の Global Interpreter Lock では一度に 1 つのスレッドしかバイトコードを実行できないため、CPU を使う並列処理には複数のプロセスが必要です(Python ドキュメント)。Go の goroutine は GIL なしですべてのコアで動き、channel でやり取りし、別個の async エコシステムを必要としません。このモデルが、Go のサービスが負荷の下でも安定している大きな理由です。
Python 開発者が Go を習得するにはどれくらいかかりますか?
基本的な構文はすぐに身につきます。関数、slice、map、パッケージは、どれも Python の知識がそのまま使えるからです。コードレビューでチームに承認されるような Go を書けるようになるには、もっと時間がかかります。Go らしいコードを形づくる要素は、Python が教えてくれなかったものだからです。値としてのエラー、小さな interface、継承ではなくコンポジション、goroutine と channel、そして標準ライブラリの慣習です。多くの開発者は、実際のプロジェクトに集中して数か月取り組んで、ようやくそれが腑に落ちます。チュートリアルを読むだけでは、「Go が読める」から「Go らしいコードが書ける」には進めません。進めるのは体系的で実践的な練習、つまり実際に何かを作り、本物の演習でフィードバックを受けることです。
バックエンド開発では、Go を学んでも Python は必要ですか?
いいえ。バックエンドの仕事なら、Go だけですべてをまかなえます。標準ライブラリには HTTP サーバー、JSON、SQL ドライバー、並行処理がフレームワークなしで揃っているので、本番環境で動くサービスをすべて Go で構築してリリースできます。インストールすべきランタイムのない単一の静的バイナリにコンパイルされ、起動が速く、goroutine で高い並行性のワークロードを処理できます。そのため、現代のインフラの多くが Go で動いています。データサイエンスや機械学習では今も Python が標準ですが、それは別の仕事です。API、マイクロサービス、CLI、インフラ用ツールであれば、Go で十分です。
今日から Go を書き始めましょう
Python の経験はここで役に立ちます。必要な考え方の型は、すでに身についています。残っているのは少数の新しいルールを身につけることで、それは Go を書くことで身につきます。エラー処理、interface、goroutine は難しくありませんが、どれも自然に感じられるまでには練習が必要です。
LevelUpGo は、そのために作られています。すべてのレッスンがブラウザ上で動く演習になっていて、書いたコードを最新の Go ツールチェーンで実行し、すぐに採点します。初日から本物の Go を書けます。
Python 開発者向けの道筋の一例です。
- 基礎から始めましょう。Go Fundamentals コースでは、最初のプログラムから関数、型、struct までを学び、エラー処理のパターンも最初から練習します。無料で始められ、クレジットカードも不要です。
- 本当に新しい唯一のモデルを学びましょう。Go Concurrency Fundamentals コースでは、goroutine、channel、
selectを学びます。Python には直接対応するものがなく、負荷がかかったときに最も効果を発揮する部分です。 - Go のやり方で書けるようになりましょう。Clean Go Code トラックでは、イディオム、命名、エラー処理を扱い、波かっこ付きの Python ではなく Go らしく読めるコードを書けるようにします。
無料のコースを始めて毎日少しずつ Go を書き、連続記録を続けましょう。
