- Python
Python randomの使い方一覧|randint・choice・shuffle
Pythonのrandomとは、乱数の生成、リストからのランダムな選択、並べ替えをおこなう標準ライブラリです。 import random と書くだけで使え、整数なら random.randint(1, 6)、1つ選ぶなら random.choice(リスト)、並べ替えなら random.shuffle(リスト) が基本です。
この記事では、「やりたいこと」から関数を引ける逆引き表を先頭に置き、randint と randrange の端の違いを60万回の度数で確認し、shuffle が None を返す理由、choice・choices・sample の重複の有無、重み付き抽選、seed による再現、パスワードやトークンに使う secrets、NumPy の default_rng との違い、空リストで出るエラーまでを扱います。コードは Python 3.14.7 で実行し、出力をそのまま載せています(NumPy の部分は Python 3.11.15 と NumPy 2.4.4)。
Python randomの早見表(やりたいこと→関数)
random.seed(42) を最初に1回呼び、上から順に実行したときの結果です。同じ順で実行すれば、同じ値が出ます。
| やりたいこと | 書き方 | 範囲・ポイント | 実行結果 |
|---|---|---|---|
| 0以上1未満の小数 | random.random() |
1.0 は含まない | 0.6394267984578837 |
| a〜b の小数 | random.uniform(1.5, 3.0) |
両端の間の小数 | 1.5375161328340003 |
| a〜b の整数(b を含む) | random.randint(1, 6) |
6 も出る | 3 |
| 0〜n-1 の整数 | random.randrange(6) |
6 は出ない(range と同じ) |
1 |
| 飛び飛びの整数 | random.randrange(0, 100, 10) |
0, 10, …, 90 | 30 |
| 1つ選ぶ | random.choice(items) |
空だと IndexError |
青 |
| 重複ありで k 個選ぶ | random.choices(items, k=5) |
同じ要素が何度も出る | ['緑', '緑', '白', '赤', '黄'] |
| 重複なしで k 個選ぶ | random.sample(items, k=3) |
k が要素数を超えると ValueError |
['赤', '白', '緑'] |
| その場で並べ替える | random.shuffle(x) |
戻り値は None。元のリストが変わる |
None |
| 元を残して並べ替える | random.sample(items, k=len(items)) |
新しいリストを返す | ['白', '緑', '赤', '青', '黄'] |
| 正規分布の乱数 | random.gauss(50, 10) |
平均 50、標準偏差 10 | 50.41656863903384 |
| 結果を再現する | random.seed(42) |
同じ種なら同じ並び | ― |
| パスワード・トークン | secrets.token_urlsafe(32) |
random ではなく secrets | ― |
items は ["赤", "青", "黄", "緑", "白"] です。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Python randomの使い方一覧|randint・choice・shuffle」
まずはコピペで動く基本形
追加のインストールは不要です。次のコードを basic.py に保存し、python basic.py で実行します。
# basic.py(Python 3.14.7 で確認)
import random
random.seed(42) # 結果を固定(外すと毎回変わる)
items = ["赤", "青", "黄", "緑", "白"]
print("random", random.random())
print("uniform", random.uniform(1.5, 3.0))
print("randint", random.randint(1, 6))
print("randrange(6)", random.randrange(6))
print("randrange(0,100,10)", random.randrange(0, 100, 10))
print("choice", random.choice(items))
print("choices", random.choices(items, k=5))
print("sample", random.sample(items, k=3))
x = items[:]
r = random.shuffle(x)
print("shuffle", r, x)
print("sample all", random.sample(items, k=len(items)), items)
print("gauss", random.gauss(50, 10))
実行結果:
random 0.6394267984578837
uniform 1.5375161328340003
randint 3
randrange(6) 1
randrange(0,100,10) 30
choice 青
choices ['緑', '緑', '白', '赤', '黄']
sample ['赤', '白', '緑']
shuffle None ['白', '緑', '黄', '赤', '青']
sample all ['白', '緑', '赤', '青', '黄'] ['赤', '青', '黄', '緑', '白']
gauss 50.41656863903384
random.seed(42) の直後の random.random() は、Python 3.11.15 でも同じ 0.6394267984578837 でした。seed の行を消すと、実行のたびに違う値になります。
整数の乱数:randintとrandrangeの端の違い
整数の乱数でいちばん間違えやすいのが、上限の値が含まれるかどうかです。
| 書き方 | 出る値 | 上限 |
|---|---|---|
random.randint(1, 6) |
1, 2, 3, 4, 5, 6 | 含む |
random.randrange(1, 6) |
1, 2, 3, 4, 5 | 含まない |
random.randrange(1, 7) |
1, 2, 3, 4, 5, 6 | 含まない(7 が出ない) |
random.randrange(6) |
0, 1, 2, 3, 4, 5 | 含まない |
random.randrange(0, 100, 10) |
0, 10, 20, …, 90 | 含まない |
60万回の度数で確認する
import random
from collections import Counter
random.seed(1)
N = 600000
print("randint(1,6) ", sorted(Counter(random.randint(1, 6) for _ in range(N)).items()))
print("randrange(1,6)", sorted(Counter(random.randrange(1, 6) for _ in range(N)).items()))
print("randrange(1,7)", sorted(Counter(random.randrange(1, 7) for _ in range(N)).items()))
randint(1,6) [(1, 100109), (2, 100009), (3, 99736), (4, 100115), (5, 100414), (6, 99617)]
randrange(1,6) [(1, 120079), (2, 120419), (3, 119664), (4, 119940), (5, 119898)]
randrange(1,7) [(1, 99972), (2, 100168), (3, 99548), (4, 100350), (5, 100239), (6, 99723)]
randrange(1, 6) では 6 が一度も出ず、1〜5 が約12万回ずつになりました。 サイコロのつもりで randrange(1, 6) と書くと、エラーにはならないまま 6 の目だけが出ない状態になります。randint(a, b) は randrange(a, b + 1) と同じ意味です。
どちらを使うかの判断表
| 状況 | 選ぶ関数 | 理由 |
|---|---|---|
| 「1から6まで」のように両端を含めて言える | randint(1, 6) |
言葉どおりに書ける |
| リストの添字を選ぶ | randrange(len(items)) |
添字は 0〜len-1。randint(0, len(items)) だと範囲外になる |
| 10刻み・偶数だけなど | randrange(0, 100, 10) |
step を指定できる |
| 要素そのものがほしい | choice(items) |
添字を経由しなくて済む |
「添字なら randrange、数の範囲なら randint」と覚えると、端の取り違えが起きにくくなります。
引数の順序と型
randint(5,1) -> ValueError empty range in randint(5, 1)
randrange(0) -> ValueError empty range for randrange()
randint(1.5,3) -> TypeError 'float' object cannot be interpreted as an integer
randrange(1.0) -> TypeError 'float' object cannot be interpreted as an integer
小さいほうを先に書き、整数を渡します。 小数を渡したときの TypeError は Python 3.12 からの動作です(公式ドキュメントで確認)。計算結果が小数になるときは int() で整数にしてから渡します。
小数の乱数:randomとuniform
| 書き方 | 範囲 | 用途 |
|---|---|---|
random.random() |
0.0 以上 1.0 未満 | 確率の判定、割合 |
random.uniform(a, b) |
a と b の間 | 任意の範囲の小数 |
round(random.uniform(0, 100), 2) |
小数第2位まで | 表示用のテストデータ |
60万回ずつ生成して、最小値と最大値を確かめました。
uniform minmax 1.0000000825686213 1.9999980832544733 ← uniform(1, 2)
random minmax 1.6923517596190152e-06 0.9999971832471999 ← random()
random() は 1.0 を返しません。uniform(a, b) の上端 b は、公式ドキュメントに「浮動小数点の丸めによって含まれることも含まれないこともある」と書かれています。
確率で分岐する
「30% の確率で当たり」は、random() と比較するだけで書けます。
if random.random() < 0.3:
print("当たり")
random() は 0 以上 1 未満を同じ確からしさで返すので、0.3 未満になる割合が 30% になります。
random() から整数を作る方法との比較
int(random.random() * 6) + 1 でも 1〜6 の整数が作れます。60万回の度数は次のとおりで、偏りは見られませんでした。
int(random()*6)+1 [(1, 99639), (2, 99985), (3, 100860), (4, 99520), (5, 99850), (6, 100146)]
ただし、意図が読み取りやすいのは randint(1, 6) です。公式ドキュメントでも、整数の範囲から選ぶ場合は randrange() 系のほうが均等な分布になると説明されています。
リストから選ぶ:choice・choices・sampleの違い
3つの関数は名前が似ていますが、「いくつ選ぶか」と「同じ要素が重複するか」が違います。
| 関数 | 選ぶ数 | 重複 | 戻り値 | 重み付け | k が要素数を超えると |
|---|---|---|---|---|---|
choice(seq) |
1個 | ― | 要素そのもの | できない | ― |
choices(seq, k=n) |
n 個 | あり(選んだものを戻して引く) | リスト | weights / cum_weights |
問題なく選べる |
sample(seq, k=n) |
n 個 | なし(選んだものは戻さない) | リスト | counts(個数指定) |
ValueError |
3要素のリストで重複を確かめる
import random
random.seed(7)
p = ["A", "B", "C"]
print("choices k=5", random.choices(p, k=5))
print("sample k=3 ", random.sample(p, k=3))
print("[choice]*5 ", [random.choice(p) for _ in range(5)])
choices k=5 ['A', 'A', 'B', 'A', 'B']
sample k=3 ['B', 'A', 'C']
[choice]*5 ['A', 'A', 'B', 'B', 'A']
choicesは重複あり。3要素から5個選べ、Aが3回出ています。sampleは重複なし。3個選ぶと、3要素がちょうど1回ずつ出ます。choiceを繰り返す書き方は、choicesと同じく重複ありです。
使い分けの判断表
| やりたいこと | 選ぶ関数 |
|---|---|
| 今日の当番を1人決める | choice(members) |
| 抽選で3人選ぶ(同じ人は1回まで) | sample(members, k=3) |
| サイコロを10回振る | choices(range(1, 7), k=10) |
| 当たりやすさに差をつけて引く | choices(items, weights=[...], k=n) |
| 1〜43 から重複なしで6個 | sample(range(1, 44), k=6) |
| ランダムな6桁の数字列(表示用) | "".join(choices("0123456789", k=6)) |
「同じものが2回出てよいか」を先に決めると、choices と sample のどちらかが自然に決まります。
重み付き抽選を10万回で検証する
choices の weights に重みを渡すと、出やすさを変えられます。重みは合計が 1 や 100 である必要はなく、比率として扱われます。
import random
from collections import Counter
random.seed(0)
c = Counter(random.choices(["大吉", "吉", "凶"], weights=[1, 6, 3], k=100000))
print(c.most_common())
c = Counter(random.choices(["大吉", "吉", "凶"], cum_weights=[1, 7, 10], k=100000))
print(c.most_common())
[('吉', 59906), ('凶', 30055), ('大吉', 10039)]
[('吉', 59758), ('凶', 30091), ('大吉', 10151)]
重み 1:6:3 に対して、結果はおよそ 10%:60%:30% になりました。 cum_weights は累積の重み(1, 1+6, 1+6+3)を渡す書き方で、結果の割合は同じです。
| 引数 | 渡すもの | 例(1:6:3) |
|---|---|---|
weights |
それぞれの重み | [1, 6, 3] |
cum_weights |
累積した重み | [1, 7, 10] |
重みの数や値が合わないときは、次のエラーになります。
ValueError The number of weights does not match the population ← 要素3つに重み2つ
ValueError Total of weights must be greater than zero ← 重みがすべて 0
重複なしで、個数に差をつけて引く:sample の counts
「当たり2本、はずれ8本のくじから5本引く(引いたくじは戻さない)」は、sample の counts(Python 3.9 以降)で書けます。
print(random.sample(["当たり", "はずれ"], counts=[2, 8], k=5))
['当たり', 'はずれ', 'はずれ', 'はずれ', 'はずれ']
["当たり"] * 2 + ["はずれ"] * 8 というリストを作って sample するのと同じ意味です。
文字列・range・辞書・集合から選ぶ
choice と sample が受け取るのは、添字で取り出せる「シーケンス」です。
| 渡すもの | choice |
対処 |
|---|---|---|
リスト・タプル・文字列・range |
選べる | そのまま渡す |
| 集合(set) | TypeError: 'set' object is not subscriptable |
sorted(s) または list(s) にする |
| 辞書(dict) | KeyError(添字の数値をキーとして探すため) |
list(d) でキーのリストにする |
choice(set) -> TypeError 'set' object is not subscriptable
sample(set) -> TypeError Population must be a sequence. For dicts or sets, use sorted(d).
choice(dict) -> KeyError 1
random.choice(range(10)) # 0〜9 から1つ
random.choice("abc") # 1文字
random.choice(list({"a": 1, "b": 2})) # キーから1つ
random.choice(sorted({3, 1, 2})) # 集合から1つ
集合を sample に渡したときの TypeError は Python 3.11 からの動作で、メッセージのとおり sorted() で並びを決めてから渡します。sorted() を使うと順序が一定になるため、seed を固定したときの再現性も保てます。
並べ替える:shuffleはNoneを返す
random.shuffle() は、渡したリストそのものを並べ替え、戻り値として None を返します。
import random
random.seed(42)
cards = [1, 2, 3, 4, 5]
res = random.shuffle(cards)
print(res, cards)
None [4, 2, 3, 5, 1]
つまずきやすい書き方と直し方
| コード | 結果 | |
|---|---|---|
| 直す前 | cards = random.shuffle(cards) |
cards が None になる |
| 直す前 | for c in random.shuffle(cards): |
TypeError: 'NoneType' object is not iterable |
| 直す前 | print(random.shuffle(cards)) |
None と表示される |
| 直した後 | random.shuffle(cards) のあとで cards を使う |
並べ替わったリストを使える |
| 直した後(元を残す) | new = random.sample(cards, k=len(cards)) |
新しいリストが返り、元は変わらない |
実際のエラーメッセージです。
TypeError 'NoneType' object is not iterable
list.sort() と sorted() の関係と同じで、「その場で変える関数は None を返す」というのが Python の決まりごとです。 shuffle は sort の仲間、と覚えると迷いません。
元のリストを残して並べ替える
orig = [1, 2, 3, 4, 5]
new = random.sample(orig, k=len(orig))
print(orig, new)
[1, 2, 3, 4, 5] [1, 5, 3, 2, 4]
タプルや文字列は shuffle できない
shuffle は要素を入れ替えるので、変更できない型を渡すとエラーになります。
TypeError 'tuple' object does not support item assignment
TypeError 'str' object does not support item assignment
タプルや文字列を並べ替えたいときは、sample で新しいリストを作ります。
print("".join(random.sample("python", k=6)))
pnyoth
seedで結果を再現する
random が返すのは擬似乱数です。「種(seed)」と呼ぶ初期値から計算で作られる数列で、同じ種からは同じ並びが得られます。
import random
for _ in range(2):
random.seed(123)
print([random.randint(1, 100) for _ in range(5)])
[7, 35, 12, 99, 53]
[7, 35, 12, 99, 53]
| 状況 | seed |
|---|---|
| ふだんの抽選・ゲーム | 呼ばない(起動時に OS の乱数源などから自動で初期化される) |
| テストや不具合の再現 | random.seed(固定の値) |
| 機械学習などで実験を比べる | 固定し、値をログに残す |
| パスワード・トークン | random ではなく secrets を使う(次の章) |
seed に渡せるのは None・int・float・str・bytes・bytearray です(Python 3.11 以降。公式ドキュメントで確認)。random.seed("abc") のように文字列も使えます。
Random インスタンスで乱数の流れを分ける
random.seed() や random.randint() は、モジュールが内部に持つ1つの共有の生成器を使っています。プログラムのあちこちで乱数を使うと、呼び出す順番が変わっただけで結果も変わります。random.Random(種) で自分専用の生成器を作ると、ほかの処理の影響を受けません。
import random
rng1 = random.Random(1)
rng2 = random.Random(1)
print(rng1.randint(1, 100), rng1.randint(1, 100), "|", rng2.randint(1, 100))
18 73 | 18
rng1 と rng2 は同じ種なので、1回目はどちらも 18 でした。それぞれが独立して進んでいます。
別のインスタンスを使っても、共有の生成器の並びは変わらないことも確かめました。
random.seed(5); a = random.random()
rng = random.Random(99); rng.random() # 専用の生成器を使う
b = random.random()
random.seed(5)
print(a == random.random(), b == random.random())
True True
| 書き方 | 生成器 | 向いている場面 |
|---|---|---|
random.seed(n) + random.xxx() |
モジュール共有 | 短いスクリプト、対話的な確認 |
rng = random.Random(n) + rng.xxx() |
自分専用 | テスト、ライブラリ、複数の乱数の流れを分けたいとき |
Random インスタンスには、randint・choice・shuffle など、モジュールの関数と同じ名前のメソッドがそろっています。関数の引数に rng を渡す形にしておくと、テストのときだけ種を固定した生成器を渡せます。
def pick_winners(members, k, rng=random):
return rng.sample(members, k=k)
pick_winners(members, 3) # ふだんは共有の生成器
pick_winners(members, 3, random.Random(0)) # テストでは固定
途中の状態を保存して戻す
st = random.getstate()
a = random.random()
random.setstate(st)
print(a == random.random())
True
パスワード・トークンにはsecretsを使う
random モジュールの公式ドキュメントには、「このモジュールの擬似乱数生成器はセキュリティ目的に使わないこと。セキュリティや暗号の用途には secrets モジュールを使うこと」という注意書きがあります。random の既定の生成器(メルセンヌ・ツイスタ)は、出力を十分な数だけ観察すると続きを計算できる仕組みだからです。
secrets は Python 3.6 から標準ライブラリに入っており、OS が提供する乱数源を使います。
import secrets
import string
print(type(secrets.token_hex(16)), len(secrets.token_hex(16)),
len(secrets.token_urlsafe(32)), len(secrets.token_bytes(16)))
print(0 <= secrets.randbelow(10) < 10, secrets.choice("abc") in "abc")
alphabet = string.ascii_letters + string.digits
pw = "".join(secrets.choice(alphabet) for _ in range(16))
print(len(pw), pw.isalnum())
<class 'str'> 32 43 16
True True
16 True
(値そのものは毎回変わるため、型と長さを表示しています。)
用途別の対応表
| 用途 | 使うもの |
|---|---|
| ゲーム・抽選・シミュレーション・テストデータ | random |
| 再現したい実験 | random.Random(seed) / numpy.random.default_rng(seed) |
| パスワードの自動生成 | secrets.choice(alphabet) を必要な文字数ぶん |
| API キー・セッション ID | secrets.token_urlsafe(32) / secrets.token_hex(32) |
| パスワード再設定用 URL のトークン | secrets.token_urlsafe() |
| 認証コード(数字6桁) | f"{secrets.randbelow(10**6):06d}" |
| トークンの比較 | secrets.compare_digest(a, b) |
random と secrets の比較
| 項目 | random | secrets |
|---|---|---|
| 乱数の種類 | 擬似乱数(計算で作る) | OS の乱数源 |
seed での再現 |
できる | できない |
| 速度 | 速い | random より遅い |
| 主な関数 | randint・choice・shuffle など多数 |
choice・randbelow・token_hex・token_urlsafe・token_bytes |
| 向く用途 | 再現性がほしい処理 | 推測されては困る値 |
secrets.SystemRandom()(random.SystemRandom と同じクラス)を使うと、OS の乱数源を使いながら shuffle や sample も呼べます。seed を呼んでも結果は固定されませんでした。
SystemRandom reproducible: False
「推測されては困る値かどうか」で分けると、選択に迷いません。
NumPyのdefault_rngとの違い
大量の乱数を配列でまとめて作るなら、NumPy が向いています。現在の NumPy では、np.random.default_rng() で生成器(Generator)を作って使う書き方が推奨されています(Python 3.11.15、NumPy 2.4.4 で確認)。
import numpy as np
rng = np.random.default_rng(42)
print(rng.random())
print(rng.random(3))
print(rng.integers(1, 7, size=10))
print(rng.integers(1, 6, size=10, endpoint=True))
print(rng.normal(50, 10, size=3))
a = np.arange(5)
print(rng.choice(a, size=3, replace=False))
r = rng.shuffle(a)
print(r, a)
print(rng.permutation(5))
print(type(rng).__name__, type(rng.bit_generator).__name__)
0.7739560485559633
[0.43887844 0.85859792 0.69736803]
[2 1 4 6 5 5 5 5 4 1]
[6 3 4 3 2 6 5 4 3 5]
[53.68750784 40.41117399 58.78450301]
[0 2 4]
None [3 2 0 4 1]
[1 2 0 4 3]
Generator PCG64
(途中の uniform と重み付き choice の行は省略して表示しています。出力は実行した順のままです。)
random と NumPy の対応表
| やりたいこと | random | NumPy(rng = np.random.default_rng()) |
|---|---|---|
| 0〜1 の小数 | random.random() |
rng.random() / rng.random(n) |
| 整数 | random.randint(1, 6)(6 を含む) |
rng.integers(1, 7)(7 を含まない) |
| 上限を含む整数 | ― | rng.integers(1, 6, endpoint=True) |
| 範囲の小数 | random.uniform(a, b) |
rng.uniform(a, b, size=n) |
| 正規分布 | random.gauss(mu, sigma) |
rng.normal(mu, sigma, size=n) |
| 重複ありで選ぶ | random.choices(x, k=n) |
rng.choice(x, size=n) |
| 重複なしで選ぶ | random.sample(x, k=n) |
rng.choice(x, size=n, replace=False) |
| 重み付き | choices(x, weights=w)(比率でよい) |
rng.choice(x, p=p)(合計 1 の確率) |
| その場で並べ替え | random.shuffle(x) |
rng.shuffle(a)(どちらも None を返す) |
| 並べ替えた新しい配列 | random.sample(x, k=len(x)) |
rng.permutation(a) |
| 種の固定 | random.seed(42) / random.Random(42) |
np.random.default_rng(42) |
違いのポイント
1. 整数の上限が逆です。 random.randint(1, 6) は 6 を含みますが、rng.integers(1, 6) は 6 を含みません。60万個の度数で確かめました。
rng.integers(1, 6) [(1, 119940), (2, 119609), (3, 120630), (4, 120127), (5, 119694)]
np.random.randint(1, 6) [(1, 119925), (2, 119661), (3, 120631), (4, 120154), (5, 119629)]
NumPy の integers も、以前からある np.random.randint も、上限を含まない動作でした。標準ライブラリの random.randint と同じ名前でも結果が違うので、書き換えるときは上限を見直します。
2. 同じ種でも、出る値は別です。 生成の仕組みが異なるためです(random はメルセンヌ・ツイスタ、default_rng は PCG64)。
random.seed(42) → 0.6394267984578837
default_rng(42) → 0.7739560485559633
3. まとめて作ると速い。 100万個の小数を作る時間は、内包表記の random.random() が 0.068 秒、rng.random(1_000_000) が 0.0036 秒で、約19倍の差でした(1回の計測の参考値です)。
4. 重複なしで多く選びすぎたときのエラー文が違います。
ValueError Cannot take a larger sample than population when replace is False
| 状況 | 向いているもの |
|---|---|
| 値を1つ、リストから数個 | 標準の random(インストール不要) |
| 数万個以上の配列、行列、統計的な分布 | np.random.default_rng() |
| pandas や機械学習の前処理 | default_rng(配列をそのまま渡せる) |
NumPy そのものの使い方は、別記事の NumPy 入門で扱っています。
空リストのIndexError・sampleのValueErrorなど、エラー一覧
実際に出したエラーメッセージ(Python 3.14.7)と対処です。
| コード | 例外とメッセージ | 対処 |
|---|---|---|
random.choice([]) |
IndexError: Cannot choose from an empty sequence |
空かどうかを先に確認する |
random.choices([], k=2) |
IndexError: list index out of range |
同上 |
random.sample([1, 2, 3], k=5) |
ValueError: Sample larger than population or is negative |
k=min(k, len(x)) にするか、重複を認めて choices を使う |
random.sample([1, 2], k=-1) |
ValueError: Sample larger than population or is negative |
k を 0 以上にする |
random.randint(5, 1) |
ValueError: empty range in randint(5, 1) |
小さいほうを先に書く |
random.randrange(0) |
ValueError: empty range for randrange() |
1 以上を渡す |
random.randint(1.5, 3) |
TypeError: 'float' object cannot be interpreted as an integer |
整数を渡す。小数なら uniform |
random.choice({1, 2, 3}) |
TypeError: 'set' object is not subscriptable |
sorted(s) にする |
random.sample({1, 2, 3}, 2) |
TypeError: Population must be a sequence. For dicts or sets, use sorted(d). |
sorted(s) にする |
random.choice({"a": 1, "b": 2}) |
KeyError |
list(d) にする |
for x in random.shuffle(a): |
TypeError: 'NoneType' object is not iterable |
shuffle のあとで a を使う |
random.shuffle((1, 2, 3)) |
TypeError: 'tuple' object does not support item assignment |
リストにするか sample を使う |
空のリストに備える書き方
import random
def pick_one(items, default=None):
"""空のときは default を返す"""
return random.choice(items) if items else default
def pick_some(items, k):
"""要素数より多く求められたら、あるだけ返す"""
return random.sample(items, k=min(k, len(items)))
検索や絞り込みの結果からランダムに選ぶ処理では、「0件だった場合」を先に決めておくと、IndexError で止まることがなくなります。
用途別のコピペレシピ
random.seed(2026) を最初に呼び、上から順に実行した結果です(Python 3.14.7)。
import random
import datetime
random.seed(2026)
# 1) 30% の確率で True
print(random.random() < 0.3)
# 2) 6桁の数字列(表示用のダミー。認証コードには secrets を使う)
print("".join(random.choices("0123456789", k=6)))
# 3) 2026年のランダムな日付
d0 = datetime.date(2026, 1, 1)
print(d0 + datetime.timedelta(days=random.randrange(365)))
# 4) メンバーを3つのグループに分ける
members = ["佐藤", "鈴木", "高橋", "田中", "伊藤", "渡辺", "山本"]
random.shuffle(members)
print([members[i::3] for i in range(3)])
# 5) 1〜43 から重複なしで6個(そのまま/昇順)
print(random.sample(range(1, 44), k=6))
print(sorted(random.sample(range(1, 44), k=6)))
# 6) テスト用の注文データ
rows = [
{"id": i, "qty": random.randint(1, 5), "price": random.randrange(100, 1000, 50)}
for i in range(1, 4)
]
print(rows)
True
558126
2026-10-12
[['佐藤', '山本', '田中'], ['鈴木', '渡辺'], ['高橋', '伊藤']]
[16, 1, 40, 6, 8, 19]
[1, 7, 14, 21, 29, 32]
[{'id': 1, 'qty': 4, 'price': 500}, {'id': 2, 'qty': 3, 'price': 650}, {'id': 3, 'qty': 4, 'price': 900}]
そのほかの関数
| 関数 | 内容 | 実行結果の例(seed(42) の続き) |
|---|---|---|
random.gauss(mu, sigma) |
正規分布。normalvariate より少し速い |
50.41656863903384 |
random.normalvariate(mu, sigma) |
正規分布。スレッドをまたいでも使える | 67.38025467335527 |
random.triangular(low, high, mode) |
三角分布 | 1.763402959120697 |
random.getrandbits(k) |
k ビットの整数 | 71 |
random.randbytes(n) |
n バイトの bytes(Python 3.9 以降) |
4 バイトの bytes |
random.binomialvariate(n, p) |
二項分布(Python 3.12 以降) | 5(seed(2026) の続きで n=10, p=0.5) |
gauss() は、複数のスレッドから同時に呼ぶと同じ値を返すことがあると公式ドキュメントに書かれています。スレッドごとに Random インスタンスを分けるか、normalvariate() を使います。
コマンドラインから使う(Python 3.13 以降)
$ python3.14 -m random 6
1
$ python3.14 -m random -c 赤 青 黄
黄
$ python3.14 -m random -f 1.5
1.2525707413419906
整数を渡すと 1〜N の整数、-c は選択、-f は 0〜N の小数です。ちょっとした抽選なら、スクリプトを書かずに済みます。
よくある質問
Q. random.randint(1, 10) と random.randrange(1, 10) の違いは何ですか?
A. 上限の 10 が出るかどうかです。randint(1, 10) は 1〜10、randrange(1, 10) は 1〜9 を返します。この記事の検証でも、randrange(1, 6) を60万回実行して 6 は一度も出ませんでした。randint(a, b) は randrange(a, b + 1) と同じ意味です。
Q. random.shuffle() の結果を変数に入れたら None になりました。なぜですか?
A. shuffle は渡したリスト自体を並べ替え、戻り値として None を返すためです。random.shuffle(cards) と単独で書き、そのあと cards を使います。元のリストを残したいときは random.sample(cards, k=len(cards)) で新しいリストを作れます。
Q. 毎回同じ乱数が出るようにするには、どうすればよいですか?
A. random.seed(42) のように種を固定します。同じ種・同じ呼び出し順なら、同じ結果になります。プログラムのほかの部分の影響を受けたくないときは、rng = random.Random(42) で専用の生成器を作り、rng.randint() のように呼びます。
Q. パスワードの生成に random.choice() を使ってもよいですか?
A. パスワードやトークンには secrets モジュールを使います。公式ドキュメントにも、random はセキュリティ目的に使わないよう書かれています。"".join(secrets.choice(alphabet) for _ in range(16)) や secrets.token_urlsafe(32) に置き換えるだけで済みます。
まとめ
- 整数は
randint(a, b)(b を含む)、添字はrandrange(n)(n を含まない)。60万回の度数で端の違いを確認した - 1つ選ぶなら
choice、重複ありで複数ならchoices、重複なしならsample - 重み付き抽選は
choices(items, weights=[...], k=n)。1:6:3 の重みで約 10%:60%:30% になった shuffleは元のリストを並べ替えてNoneを返す。元を残すならsample(x, k=len(x))- 再現したいときは
seed、流れを分けたいときはrandom.Random(種) - パスワード・トークンは
secrets。推測されては困る値かどうかで分ける - NumPy の
rng.integers(1, 6)は 6 を含まない。randintと上限の扱いが逆なので、書き換え時に見直す
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Python randomの使い方一覧|randint・choice・shuffle」
株式会社RJCでは、Pythonの乱数や標準ライブラリの使い方を仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。