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行足してみてください。


あわせて読みたい

プログラミング学習に興味がある方は、まずは無料体験会へ

無料体験会・お申し込みはこちら