LoginSignup
0
0

More than 1 year has passed since last update.

secrets.randbelowをrandintのように使いたい

Last updated at Posted at 2021-10-18

結論

# randint(a,b)の代わり
secretsRandint = lambda a,b: (secrets.randbelow((b-a)+1))+a
# choices(l, k=n)の代わり
secretsChoices = lambda table, k: [secrets.choice(table) for _ in range(k)]

背景

Pythonで乱数を生成する際にはrandom.randintが使えます。しかし、この関数は簡単な規則で乱数を生成されています。このため、パスワードの精製などにはsecretsモジュールの仕様が推奨されます。
ただし、secretsモジュールの関数はrandomと少し異なります。同じように使えるようにします。

randint(a,b)

予備知識: []は閉区間で以上・以下です。()は開区間で超過・未満です。

  • random.randint(a,b) は [a,b]を返します。random.randint(4,7) なら 4,5,6,7が出ます。
  • secrets.randbelow(n) は [0,n)を返します。secrets.randbelow(4) は 0,1,2,3が出ます。

ここでrandomのように(a,b)の区間を返したい場合、

  • secrets.randbelow( (b-a)+1) ) + a とします。

例: secretsで4,5,6,7を返したい場合、

  • secrets.randbelow( (7-4)+1) ) + 4 と代入し
  • secrets.randbelow( 4 ) + 4 となる。
  • これは、(0,1,2,3)の一様に出現するランダムな集合に+4なので、結果(4,5,6,7)となる

実装例

import secrets
secretsRandint = lambda a,b: (secrets.randbelow((b-a)+1))+a
import collections
# Counter({1: 2020, 2: 2011, 5: 2008, 3: 1992, 4: 1969}) のように一様にランダムに選択されている
print(collections.Counter([secretsRandint(1,5) for _ in range(10000)]))

choices

# ['1', '7', '2', '5', '3', '2', '3', '7', '6', '3']
import string, random
random.choices(string.digits, k=10)

となる便利な関数です。なぜかsecretsにはchoiceという1文字をランダムに取り出す関数しかありません。n回呼べばよいです。

実装例

secretsChoices = lambda table, k: [secrets.choice(table) for _ in range(k)]
# ['6', '1', '6', '0', '9', '7', '3', '1', '8', '7']
print(secretsChoices(string.digits, 10))
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0