Python运算(四)random模块&secrets模块

random模块

random模块实现了这种分布的伪随机数生成器,随机数可以被应用于数学、安全等领域,并且也经常被嵌入算法中,用以提高算法效率,在机器学习算法中对随机数的设定是必要的一步,并且随机数的设定会影响算法的好坏。

random模块提供的函数是基于random.Random类的隐藏实例的绑定方法,几乎所有模块函数都依赖于基本函数random()random()函数在半开放区间[0.0, 1.0)内均匀生成随机浮点数。用Randon类作为子类,重写 random()seed()getstate() 以及 setstate() 方法可以自己设计不同随机生成器。

random针对整数,范围有统一的选择;针对序列,随机元素统一选择、存在用于生成列表的随机排列函数,以及用于随机抽样而无需替换的函数;针对实数轴,有计算均匀、正态(高斯)、对数正态、负指数、伽马和贝塔分布的函数,生成角度分布,可以使用von Mises分布。

Bookkeeping 函数

函数 释义
random.seed(a=None, version=2) 初始化随机数生成器,如果a被省略为或为None,则使用当前系统时间。如果提供随机源,则使用提供的随机源,如果a是int类型,则直接使用。
random.getstate() 捕获随机生成器当前内部状态的对象,可以将该对象传递给setstate()来恢复状态
random.setstate(state) state是调用getstate()获得,并且setstate()将生成器的内部状态恢复到getstate()被调用时候的状态
random.getrandbits(k) 返回带有K位随机的Python整数,此方法随MersenneTwister生成器一起提供其他一些生成器也可以将其作为API的可选部分提供(注:Python 使用 Mersenne Twister 作为核心生成器。 它产生 53 位精度浮点数,周期为 2**19937-1)。

整数随机函数

函数 释义
random.randrange(stop) 返回不高于stop的一个随机数
random.randrange(start, stop, step) range(start, stop, step) 返回一个随机选择的元素,相当于 choice(range(start, stop, step)) ,但实际上并没有构建一个 range 对象,在 3.2 版更改: randrange() 在生成均匀分布的值方面更为复杂
random.randint(a,b) 返回随机满足a<=N<=b的随机整数N。相当于 randrange(a, b+1)
>>> import random
>>> random.randrange(100)
94
>>> random.randrange(0, 100, 3)
81
>>> random.randint(0, 10)
4

序列随机函数

函数 释义
random.choice(seq) 从非空序列 seq 返回一个随机元素。 如果 seq 为空,则引发 IndexError
random.choices(population, weights =None, *, cum_weights=None, k = 1 ) population中选择替换,返回大小为 k 的元素列表。 如果 population 为空,则引发 IndexError。如果指定了weight序列,则根据相对权重进行选择。或者,如果给出 cum_weights 序列,则根据累积权重(可能使用 itertools.accumulate() 计算)进行选择。 例如,相对权重[10, 5, 30, 5]相当于累积权重[10, 15, 45, 50]。 在内部,相对权重在进行选择之前会转换为累积权重,因此提供累积权重可以节省工作量。如果既未指定 weight 也未指定 cum_weights ,则以相等的概率进行选择。 如果提供了权重序列,则它必须与 population 序列的长度相同。weightscum_weights 可以使用任何与 random() 返回的 float 值互操作的数值类型(包括整数,浮点数和分数但不包括十进制小数
random.shuffle(x, random) 将序列x随机打乱位置。可选参数 random 是一个0参数函数,在 [0.0, 1.0) 中返回随机浮点数;默认情况下,这是函数 random() 。要改变一个不可变的序列并返回一个新的打乱列表,请使用sample(x, k=len(x))
random.sample(poplation, k) 返回从总体序列或集合中选择的唯一元素的 k 长度列表。 用于无重复的随机抽样。返回包含来自总体的元素的新列表,同时保持原始总体不变。 结果列表按选择顺序排列,因此所有子切片也将是有效的随机样本。 这允许抽奖获奖者(样本)被划分为大奖和第二名获胜者(子切片)。要从一系列整数中选择样本,请使用 range() 对象作为参数。 对于从大量人群中采样,这种方法特别快速且节省空间:sample(range(10000000), k=60)
>>> random.choice(['win', 'lose', 'draw'])
'lose'
>>> deck = 'one two three foure'.split()
>>> random.shuffle(deck)
>>> deck
['three', 'two', 'one', 'foure']
>>> random.sample([23,12,45,23,45,678,34,75], k = 4)
[23, 75, 34, 23]

分布函数

函数 释义
random.random() 返回[0.0, 1.0)范围内的一个随机浮点数
random.uniform(a,b) 返回一个随机浮点数 N ,当 a <= ba <= N <= b ,当 b < ab <= N <= a
random.triangular(low,high,mode) 返回一个随机浮点数N,使得low <= N <= high 并在这些边界之间使用指定的 modelowhigh 边界默认为零和一。 mode 参数默认为边界之间的中点,给出对称分布
random.betavariate(alpha,beta) Beta分布,参数alpha、beta都必须>0,返回的范围介于0~1之间
random.expovariate(lambd) 指数分布,lambd是1.0除以所需的平均值,非零。如果lambd为正,则返回0到正无穷;如果lambd为负,则返回负无穷到0。
random.gammavariate(alpha,beta) Gmma分布,参数alpha和beta必须>0。
random.gauss(mu,sigma) 高斯分布,mu是平均值,sigma是标准差
random.lognormvariate(mu,sigma) 对数正态分布,如果采用的是自然对数,则会得到平均值为mu,方差为sigma的正态分布,mu可以是任何职,sigma必须大于零
random.normalvariate(mu, sigma) 正态分布,mu是平均值,sigma是标准差
random.vonmisesvariate(mu, kappa) mu是平均角度,以弧度表示,介于0和2pi之间,kappa是浓度参数,必须大于或等于零,如果kappa等于零,则该分部在0到2\pi的范围内较少到均匀的随机角度。
random.paretovariate(alpha) 帕累托分布,alpha是形状参数
random.weibullvariate(alpha, beta) 威布尔分布,alpha是比例参数,beta是形状参数

Gmma分布的概率函数为:

​ $pdf(x) = \dfrac{x^{(alpha-1)}\times math.exp(\dfrac{-x}{beta})}{math.gamma(alpha)\times beta^ {alpha}}$

>>> import random
>>> random.random()
0.024784298572476104
>>> random.uniform(2.0, 5.0)
3.4259267542329748
>>> random.triangular(0.3, 1.5, 0.9)
1.1348586558465164
>>> random.betavariate(0.3, 0.25)
0.9983372793378633
>>> random.expovariate(3.0)
1.680963868987473
>>> random.gammavariate(0.25, 2.0)
0.0888430548880927
>>> random.gauss(13, 2.64)
14.755902455467584

替代随机生成器

使用os.urandom()函数的类,用从操作系统提供的源生成随机数,但这并非适用于所有的系统,也不依赖于软件的序列状态,生成的序列不可再现,因此导致seed()方法没有效果而被忽略,getstate()和setstate()函数被调用会引发NotImplementedError。因此random模块提供了替代随机生成器:

random.SystemRandom(seed)

随机序列重现问题

有的时候需要重现伪随机数生成器给出的序列,这在一些特殊情况下有着特殊的作用,通过重新使用新种子值,只要没有多个线程同时运行,相同的序列就可以在两次不同运行之间重现。

多数的随机模块算法和种子函数都会在Python版本中发生变化,但不变的方面有两个:

. 如果添加了新的生成方法,则会提供向后兼容的随机生成器

. 当兼容的生成器被赋予相同种子,生成器的random()方法将会产生相同的序列

secrets模块

虽然random模块可以生成随机数,但是并不能对生成随机数的种子、随机机制、生成的随机序列进行加密。而secrets模块就是专门用来为管理像密码、验证码、加密token等需要加密数据而生成具有非常强加密性的随机数字。

加密随机数函数

secrets模块能够提供最强的能够操作系统提供的加密随机性资源。其访问和生成函数如下:

函数 释义
secrets.SystemRandom 生成加密系统随机函数生成器
secrets.choice(sequence) 从非空序列sequence中随机返回一个元素
secrets.randbelow(n) 返回[0,n)范围内的随机数
secrets.randbits(k) 随机返回一个bit长度为k的整数

生成tokens

secrets模块为密码以及网络访问提供了生成token函数

函数 释义
secrets.token_bytes(nbytes=None) 随机返回字节数长度为nbytes值的字节形式的字符串,如果nbytes=None则使用默认的nbytes长度
secrets.token_hex(nbytes=None) 随机返回文本长度为nbytes的文本字符串,如果nbytes=None则使用默认的nbytes长度
secrets.token_urlsafe(nbytes=None) 随机返回URL-safe文本字符串,文本形式经过Base64转换,如果nbytes=None则使用默认的nbytes长度
>>> import secrets
>>> secrets.token_bytes(16)
b'\xe4\xef\x0e`\xf6k\xda\x01\xc2\xd0\x94L\x84B\xe2v'
>>> secrets.token_hex(16)
'1e702fc2ed63e4e08d2b075d62b6e782'
>>> secrets.token_urlsafe(16)
'EsZPaNvSuNKw6XpHr6xCCQ'

token字节长度问题

关于token字节长度问题过去很长一段时间没有得到明确的值,直到2015年,32个字节(256bits)长度确定为是token最能接受的高效的长度。如果想要更改token字节长度,就需要给出token的长度。

字节比较功能

secrets模块中的secrets__compare_digest__(a,b)函数可以用来进行字节或字符的比较,如果a和b是一样的,则返回Ture,如果不同则返回False

secrets 练习

>>> import string
>>> alphabet = string.ascii_letters + string.digits
>>> while True:
    password = ''.join(secrets.choice(alphabet) for i in range(10))
    if(any(c.islower() for c in password) and any(c.isupper() for c in password) and sum(c.isdigit() for c in password) >= 3):
        break