Python random.seed()とは?乱数を固定して再現する方法
Pythonのrandom.seed()は、乱数の「出方」を固定する関数です。
乱数は本来、実行するたびに違う値になります。しかしseed()を使うと、何度実行しても毎回まったく同じ乱数の並びを再現できます。
「テストのたびに結果が変わって困る」「機械学習の実験結果を再現したい」といった場面で必ず登場する関数です。この記事では、その仕組みと使いどころを解説します。
random.seed()の基本的な使い方
まずはseed()を使わない場合を見てみます。
import random
print([random.randint(1, 6) for _ in range(5)])
実行結果(例):
[2, 5, 1, 6, 3]
これを2回、3回と実行すると、そのたびに違う並びが出ます。
次に、seed()を付けてみます。
import random
random.seed(0)
print([random.randint(1, 6) for _ in range(5)])
random.seed(0)
print([random.randint(1, 6) for _ in range(5)])
実行結果:
[4, 4, 1, 3, 5]
[4, 4, 1, 3, 5]
まったく同じ並びになりました。
しかもこれは、あなたの環境で実行しても同じ結果になります。random.seed(0)のあとの5回のサイコロは、Pythonであればいつ・どこで実行しても[4, 4, 1, 3, 5]です。
なぜ同じ結果になるのか
randomモジュールが作る乱数は、正確には「擬似乱数」と呼ばれます。
サイコロを振っているのではなく、ある数から計算で次の数を作り出しているだけです。
| 用語 | 意味 |
|---|---|
| シード(seed) | 計算の出発点になる数 |
| 擬似乱数 | 計算で作られた、ランダムに見える数列 |
出発点が同じなら、そこから計算される数列も当然すべて同じになります。これがseed()で結果を再現できる理由です。
「乱数の並びが書かれた巨大な本があり、シードは何ページ目から読み始めるかを決める数字」とイメージすると分かりやすくなります。
シードを指定しないとどうなるか
seed()を一度も書かない場合、Pythonは起動時に自動でシードを決めています。
この自動のシードにはOSが提供する予測困難な値(利用できない環境では現在時刻)が使われるため、実行のたびに違う結果になります。
意図的に「毎回違う結果」に戻したいときは、引数なしで呼び出します。
import random
random.seed(42)
print(random.randint(1, 100))
random.seed() # 自動のシードに戻す
print(random.randint(1, 100))
実行結果(例):
82
39
1行目は必ず82になりますが、2行目は実行のたびに変わります。
シードに使える値
シードには整数だけでなく、文字列やバイト列も使えます。
import random
random.seed("techgym")
print([random.randint(1, 100) for _ in range(3)])
実行結果:
[7, 82, 10]
| シードの型 | 使える | 例 |
|---|---|---|
| int | ○ | random.seed(42) |
| str | ○ | random.seed("abc") |
| bytes | ○ | random.seed(b"abc") |
| float | ○ | random.seed(3.14) |
| None | ○(自動) | random.seed() |
| list | × | TypeError |
文字列が使えるので、ユーザー名や日付をシードにするといった使い方もできます。
import random
# 同じ日なら全員に同じ「今日のラッキーカラー」を出す
colors = ["赤", "青", "黄", "緑", "紫"]
random.seed("2026-09-15")
print(random.choice(colors))
実行結果:
青
seed()はrandom関数すべてに効く
seed()が固定するのはrandint()だけではありません。randomモジュールの関数すべてが対象です。
import random
random.seed(42)
cards = [1, 2, 3, 4, 5]
random.shuffle(cards)
print(cards)
random.seed(42)
print(random.sample(range(1, 46), 6))
実行結果:
[4, 2, 3, 5, 1]
[41, 8, 2, 18, 16, 15]
shuffle()の並び順も、sample()の抽選結果も固定されます。
ここで大事なのは、シードを指定するのは1回だけで、そのあとの乱数は「呼んだ順番」で決まるという点です。
import random
random.seed(1)
print(random.randint(1, 10), random.randint(1, 10))
random.seed(1)
print(random.randint(1, 10))
print(random.randint(1, 10))
実行結果:
3 10
3
10
途中に乱数を使う処理を1つ挟むだけで、それ以降の値はすべてずれます。「シードを固定したのに結果が変わる」ときは、間に別の乱数処理が入っていないかを疑ってください。
使いどころ①:テストで結果を固定する
乱数を使う関数はテストが書きにくくなります。実行するたびに答えが変わるからです。
import random
def draw_lottery(members):
return random.choice(members)
members = ["田中", "佐藤", "鈴木", "高橋"]
random.seed(100)
print(draw_lottery(members))
random.seed(100)
print(draw_lottery(members))
実行結果:
佐藤
佐藤
シードを固定すれば「この入力ならこの結果になるはず」というテストが書けます。
使いどころ②:実験結果を再現する
機械学習では、データの分割やパラメータの初期値に乱数を使います。シードを固定しないと、同じコードなのに毎回スコアが変わることになります。
import random
random.seed(42)
data = list(range(1, 21))
random.shuffle(data)
train = data[:15]
test = data[15:]
print("学習用:", train)
print("検証用:", test)
実行結果:
学習用: [20, 6, 15, 5, 10, 14, 16, 19, 7, 13, 18, 11, 2, 12, 3]
検証用: [17, 8, 9, 1, 4]
シードを書いておけば、数か月後でも他人の環境でも、まったく同じ分割を再現できます。
なお、NumPyやPyTorchなど外部ライブラリは、それぞれ別の乱数を持っています。random.seed()だけでは固定できないため、ライブラリごとの指定も必要です。
import random
import numpy as np
random.seed(42)
np.random.seed(42) # NumPyは別途指定が必要
getstate()とsetstate()で途中から再現する
seed()は「最初から」やり直す関数です。処理の途中の状態を保存して戻したいときは、getstate()とsetstate()を使います。
import random
random.seed(7)
print(random.random())
state = random.getstate() # 現在地を保存
print(random.random())
random.setstate(state) # 保存した地点に戻す
print(random.random())
実行結果:
0.32383276483316237
0.15084917392450192
0.15084917392450192
2回目と3回目が同じ値になりました。「しおりを挟んで、あとでそのページに戻る」ようなイメージです。
Randomクラスで乱数を分ける
random.seed()はプログラム全体で共有される乱数を書き換えます。そのため、ライブラリの内部処理まで巻き込んで固定してしまうことがあります。
影響範囲を限定したいときは、random.Random()で独立した乱数生成器を作ります。
import random
rng = random.Random(42) # 独立した生成器
other = random.Random(42) # 同じシードなら同じ並び
print([rng.randint(1, 10) for _ in range(3)])
print([other.randint(1, 10) for _ in range(3)])
# 全体のrandomには影響しない
print(random.randint(1, 10))
実行結果(3行目は毎回変わります):
[2, 1, 5]
[2, 1, 5]
8
ライブラリを書く場合や、複数の乱数系列を独立させたい場合はこちらが安全です。
seed()を使ってはいけない場面
シードを固定すると、乱数は完全に予測可能になります。
そのため、以下の用途では絶対に使わないでください。
- パスワードや初期パスワードの生成
- 認証トークン、セッションID
- 暗号鍵
- 金銭が絡む抽選
「時刻をシードにすれば安全だろう」と考えるのもNGです。発行時刻が分かればシードも分かってしまいます。
import time
import random
# NG: 時刻からシードを作る
random.seed(int(time.time()))
print(random.randint(100000, 999999))
セキュリティが関わる場面では、secretsモジュールを使います。secretsにはseed機能自体がありません。再現できないことこそが安全性だからです。
import secrets
# 安全な6桁のコード
print(secrets.randbelow(900000) + 100000)
実行結果(例):
472913
random.seed()のまとめ
random.seed()は乱数の出発点を固定し、同じ並びを再現する- 引数なしで呼ぶと自動のシードに戻る
- 整数だけでなく文字列やバイト列もシードにできる
shuffle()やsample()などrandom全体に効く- 途中から再現するなら
getstate()/setstate() - 影響範囲を絞るなら
random.Random() - パスワードや認証には使わない(
secretsを使う)
「テストが安定しない」「実験が再現できない」と感じたら、まずrandom.seed()を1行足してみてください。



