順番に読み進めながら学べます

random と secrets — 乱数の使い分け

Python の random / secrets モジュールを基礎から解説します。random.choice / randint / shuffle と seed による再現可能な疑似乱数、secrets.token_hex / token_urlsafe による暗号学的に安全なトークン、テスト用とセキュリティ用の使い分け基準まで、ハンズオンで学べます。

乱数を扱う 2 モジュール を整理します。randomテスト・ゲーム・シミュレーション用の疑似乱数seed で再現可能)、secretsパスワードリセットトークン・API キーなどセキュリティ用の予測不能な乱数(OS 提供の暗号乱数源)。用途で必ず使い分ける のが鉄則です。

random と secrets の違い

両モジュールは「乱数を返す」点では同じですが、仕組みと用途が完全に分かれていますrandomメルセンヌ・ツイスター(広く使われている疑似乱数生成アルゴリズム)で、random.seed(値) を呼べば 同じ並びを再現 できます。一方 secretsOS が提供する暗号乱数源/dev/urandom 等)から取得するので、`seed` の概念はなく、毎回予測不能 な値が返ります。

テストやゲームのように「結果が外部に漏れても被害が出ない」場面では random、パスワード・トークン・セッション ID のように「外部に予測されたら被害が出る」場面では secrets を使う、と覚えてください。

random と secrets の使い分け
random再現可能な疑似乱数seed で同じ並びゲーム / テストシミュレーションsecrets予測不能な暗号乱数seed 不可トークン / パスワードセッション ID
random再現できる疑似乱数 — テスト・ゲーム向け。secretsOS の暗号乱数源 から取る予測不能な乱数 — トークン・パスワード生成向け。用途で必ず使い分ける こと。
観点randomsecrets
乱数源メルセンヌ・ツイスター (アルゴリズム)OS の暗号乱数源 (/dev/urandom 等)
再現性seed で同じ並びを再現できる再現不可 (毎回違う値)
速度高速比較的遅い (用途的に問題にならない)
向く用途テスト・ゲーム・シミュレーショントークン・パスワード・セッション ID

random — 基本の乱数 (randint / uniform / choice)

random モジュールの基本は 整数の乱数 / 小数の乱数 / リストから 1 件選ぶ の 3 つです。random.randint(下限, 上限)両端を含む整数random.uniform(下限, 上限)指定範囲の floatrandom.choice(リスト)リストから要素を 1 つ取り出す ことができます。

まずは seed を使わずに、これらの基本関数の振る舞いを確認します。

random の基本関数
random.randint(a, b)→ a〜b の整数random.uniform(a, b)→ a〜b の floatrandom.choice(リスト)→ 要素 1 つ
randint は範囲内の整数(両端含む)、uniform は範囲内の小数、choiceリストから要素を 1 つ取り出す 関数。どれも入力と戻り値の形が違うので、用途に合わせて選ぶ。
関数戻り値使いどころ
random.randint(a, b)a 〜 b の整数 (両端含む)サイコロ、テスト用 ID
random.uniform(a, b)a 〜 b の floatノイズ、確率的シミュレーション
random.choice(seq)シーケンスから 1 つメニューから 1 件抽出

random の基本関数 3 つ を試します。乱数なので毎回値は違いますが、範囲や所属の判定 で正しく動いていることを確認します。

① random を読み込んでください

random.randint1〜100 の整数 を 1 つ生成し n に入れ、random.uniform0〜1 の float を生成して f に入れ、random.choice["Apple", "Banana", "Cherry"] から 1 件選んで picked に入れてください

n1〜100 の範囲内f0〜1 の範囲内picked元のリストに含まれている か、それぞれ 整数の範囲: True / Falsefloat の範囲: True / Falseリスト内: True / False の形で表示してください

(正しく実行できれば解説が表示されます)

Python エディタ

コードを実行してください

random — シードによる再現性とコレクション操作

ここからは random.seed によるテスト再現性と、コレクション操作系の関数shuffle / sample)を扱います。random.seed(N) を呼んでから乱数関数を使うと 同じシード値なら必ず同じ並びの値 が出ます。random.shuffle(リスト)元のリストの並びをランダムに入れ替えrandom.sample(リスト, k)重複なしで k 件取り出した新しいリスト を返します。

seed / shuffle / sample
random.seed(値)→ 内部状態を固定再現性が出るrandom.shuffle(リスト)→ 元を並べ替え戻り値は Nonerandom.sample(リスト, k)→ 重複なし k 件新しいリスト
seed(値) は内部状態を固定するので 同じ並びが再現 できる。shuffle元のリストを破壊的に並べ替える(戻り値は None)。sample重複なしで k 件取り出した新しいリスト を返す(元は変えない)。
関数戻り値使いどころ
random.seed(value)None (内部状態を初期化)テストの再現性確保
random.shuffle(seq)None (元のリストを並べ替える)リストの順番をランダムに入れ替える
random.sample(seq, k)重複なし k 件のリストアンケートから k 人抽選

シード 42 で生成した値と、シードを戻してもう一度生成した値が一致するか を確認します。

① random を読み込んでください

② シード 42 を設定してから random.randint(1, 100) を 1 回呼んで n1 に入れてください

③ もう一度シード 42 を設定してから random.randint(1, 100) を呼んで n2 に入れてください

再現性: True の形で n1 == n2 を表示してください

Python エディタ

コードを実行してください

shuffle はリスト自体を並べ替え、sample は新しいリストを返す 違いを確かめます。

① シード 7 を設定し、cards = [1, 2, 3, 4, 5] を用意してください

random.shuffle(cards) を呼んで、cards の中身を そのままの場所で 並べ替えてください。並べ替え後の cards並べ替え後: ◯◯ の形で表示してください

③ シードをもう一度 7 に戻したうえで random.sample([1, 2, 3, 4, 5], 3)重複なし 3 件 を取り出して、結果を 抽選 3 件: ◯◯ の形で表示してください

Python エディタ

コードを実行してください

secrets — セキュリティに使える強い乱数

前セクションの randomテスト用の疑似乱数 で、内部状態が漏れると次の値が予測されてしまいます。パスワードリセットトークン・API キー・セッション ID のような「攻撃者に予測されたら被害が出る用途」では、OS 提供の暗号学的乱数源を使う secrets モジュール を選びます。

secrets の API は random よりずっと小ぶりで、ランダムなバイト列を 16 進文字列や URL セーフな文字列に変換するヘルパー関数 が中心です。

関数戻り値使いどころ
secrets.token_bytes(n)n バイトのランダムな bytes暗号鍵、内部用バイナリトークン
secrets.token_hex(n)2*n 文字の 16 進文字列ログインセッション ID
secrets.token_urlsafe(n)URL セーフな文字列 (Base64 風)リセットリンクの URL に埋める
secrets.choice(seq)seq から暗号学的に 1 件ランダム表示順を予測されたくない場面
secrets.compare_digest(a, b)True / False (タイミング攻撃耐性)ハッシュ・トークン比較 (== の代わり)

secrets でセキュリティ用トークンを生成し、長さや文字種を確かめます。実際の値は毎回違うので、長さなどのプロパティで検証します。

① secrets を読み込んでください

② 16 バイトの 16 進トークン を生成し、hex 文字数: ◯ の形で長さを表示し、続けて hex は 16 進のみ: True / False の形で 0〜9 と a〜f 以外の文字が含まれていない かを表示してください

③ 16 バイトの URL セーフトークン を生成し、urlsafe 文字数: ◯ の形で長さを表示してください

Python エディタ

コードを実行してください
QUIZ

理解度チェック

まずは1問ずつ答えてみましょう。

Q1パスワードリセットトークン を生成するときに使うべきモジュールはどれですか?

Q2random.seed(42) を呼んでから random.randint(1, 100) を実行し、もう一度同じことをする と何が起きますか?

Q3ランダムに並び替えたリストをテスト用に再現できるようにしたい とき、最も適切なのはどれですか?