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

random と secrets — 乱数の使い分け

random.randint/choice/shuffle/sampleと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ランダムに並び替えたリストをテスト用に再現できるようにしたいとき、最も適切なのはどれですか?