random——模块
2018-02-14 18:02
211 查看
random——产生伪随机数
模块用途
random 模块是为各种分布实现伪随机数发生器。几乎模块中所有函数都依赖于基本函数random(),它在半开放范围[0.0,1.0)内产生一个统一的随机浮点数。Python使用Mersenne Twister作为核心生成器。它生成53位精度浮点数,周期为2**19937-1.C中的底层实现即快速又线程安全。
注:Mersenne Twister是存在的最广泛测试的随机数发生器之一。但是,这是完全确定性的,并不适用于所有目的,并且完全不适合加密的目的
警告:该模块的伪随机生成器不应用于安全目的。为了安全或加密使用
_randbelow()的部分源码
BPF = 53 # 返回一个小于n的随机数(计算随机数的实例) def _randbelow(self, n, int=int, maxsize=1<<BPF, type=type, Method=_MethodType, BuiltinMethod=_BuiltinMethodType): "Return a random int in the range [0,n). Raises ValueError if n==0." random = self.random # 将父类的random方法赋值给random getrandbits = self.getrandbits # 将父类的getrandbits方法赋值给getrandbits # 如果原始的random()内置方法没有被覆盖 或者 提供了一个新的getrandbits() 才可以调用self.getrandbits if type(random) is BuiltinMethod or type(getrandbits) is Method: # 如果 random 是内置函数 或 getrandbits 是 方法 # k 是 开始位置转换成二进制的长度 k = n.bit_length() # don't use (n-1) here because n can be 1 # 计算 一个随机数 r = getrandbits(k) # 0 <= r < 2**k while r >= n: r = getrandbits(k) # 返回一个小于n的随机数 return r # 如果复写了random()方法但是没有复写getrandbits()方法 我们只能用自己的random()方法 if n >= maxsize: # 如果n >= maxsize (maxsize = 9007199254740992) 就调用random()方法 _warn("Underlying random() generator does not supply \n" "enough bits to choose from a population range this large.\n" "To remove the range limitation, add a getrandbits() method.") return int(random() * n) # random() 方法 是 随机[0,1) 的一个数 rem = maxsize % n limit = (maxsize - rem) / maxsize # int(limit * maxsize) % n == 0 r = random() # r < liimit while r >= limit: r = random() return int(r*maxsize) % n
随机整数
random.randrange(self, start, stop=None, step=1, _int=int)
start: 起始数值stop=None:结束数值 默认为 None
step=1步长 默认为1
random.randrange(10)
——产生一个[0,10)的随机整数import random print(random.randrange(10)) 5
以下为randrange部分源码
def randrange(self, start, stop=None, step=1, _int=int): istart = _int(start) if istart != start: raise ValueError("non-integer arg 1 for randrange()") # 如果stop是空 即 我们只传了一个参数即 random.randrange(10) if stop is None: if istart > 0: # 返回一个小于 start 的 随机数 return self._randbelow(istart) raise ValueError("empty range for randrange()")
random.randrange(10)
如果我们传入的参数是一个大于0的数字,就会通过_randbelow(10)进行运算得到返回值
random.randrange(5,20)
——产生一个[5,20)的随机整数import random print(random.randrange(5, 20)) 7
以下是randrange部分源码
def randrange(self, start, stop=None, step=1, _int=int): # stop argument supplied. istop = _int(stop) if istop != stop: raise ValueError("non-integer stop for randrange()") width = istop - istart # 范围 是一个整数 if step == 1 and width > 0: # 如果步长等于1 且 范围大于零 # 返回 一个 start + 小于范围的随机数 return istart + self._randbelow(width) # _randbelow()方法见上面 if step == 1: # 如果范围 <= 0 则抛出以下异常 具体示例 见 Lrandrange_E1 raise ValueError("empty range for randrange() (%d,%d, %d)" % (istart, istop, widt 4000 h))
random.randrange(5,20)
如果我们传入的参数为x, y 且(y - x )> 0 就会通过x + _randbelow(y - x) 进行运算得到返回值
Lrandrange_E1
import random print(random.randrange(1,1,1)) Traceback (most recent call last): File "D:/random_demo.py", line 20, in <module> print(random.randrange(1,1,1)) File "D:/random_demo.py", line 198, in randrange raise ValueError("empty range for randrange() (%d,%d, %d)" % (istart, istop, width)) ValueError: empty range for randrange() (1,1, 0)
random.randrange(5,-1,-2)
——产生(5,-1,-2)的随机数import random print(random.randrange(5,-1,-2)) 3
random.randrange(5,20,5)
——产生(5,20,5)的随机数import random print(random.randrange(5, 20, 5)) 10
以下是randrange部分源码
def randrange(self, start, stop=None, step=1, _int=int): istep = _int(step) if istep != step: raise ValueError("non-integer step for randrange()") # 要么 start < stop and istep > 0 # 要么 start > stop and istep < 0 # 其余情况报错 if istep > 0: # width = istop - istart n = (width + istep - 1) // istep elif istep < 0: n = (width + istep + 1) // istep else: raise ValueError("zero step for randrange()") if n <= 0: raise ValueError("empty range for randrange()") # 返回 start + 步长 * 小于n的随机整数 return istart + istep*self._randbelow(n)
如果我们传入的参数为为x, y, z
( z < 0 )且(y - x )< 0 就会通过x + z * _randbelow((y - x + 1) // z) 进行运算得到返回值
( z > 0 )且(y - x )> 0 就会通过x + z * _randbelow((y - x - 1) // z) 进行运算得到返回值
((y - x + 1) // z) 是计算了 可取的范围(其实就是计算了[x, y)这个范围中有最多可取到多少个z)
根据这个数取一个小于它的随机数然后乘步长 + x
random.randint(a,b)
返回一个随机整数N使得。别名 。a <= N <= b``randrange(a, b+1)
def randint(self, a, b): """Return random integer in range [a, b], including both end points. """ return self.randrange(a, b+1)
so~ randint() 其实就是调用了 randrange()方法 也就是一个简化版的randrange()
序列函数
random.choice(self, seq)
——在一个非空的序列中选择一个元素import random print(random.choice([1,2,3])) 1
源码如下
def choice(self, seq): try: # 选择一个随机索引 i = self._randbelow(len(seq)) except ValueError: # 如果序列为空 则抛出异常 raise IndexError('Cannot choose from an empty sequence') # 通过索引找到随机的元素 return seq[i]
random.choice([1,2,3])
在这个list列表中 根据列表的长度随机算出一个小于列表长度的数作为索引,返回该索引的值
random.shuffle(self, x, random=None)
将序列x随机混合(将x随机打乱)import random l = [12,11,10] random.shuffle(l) print(l) [12, 10, 11]
源码如下
def shuffle(self, x, random=None): ''' x 列表(可迭代对象) random 是一个 计算随机数的方法 ''' # random 为空 即 我们没有手动传入一个计算随机数的方法 if random is None # 赋予self._randbelow方法 一个别名 randbelow randbelow = self._randbelow # 循环 len 次每次将索引为i的 值 和 索引为 一个小于i的随机整数的值进行替换 for i in reversed(range(1, len(x))): # 通过self._randbelow方法进行计算随机数得到j的值 j = randbelow(i+1) # 交换 索引为i 和索引为j的值 x[i], x[j] = x[j], x[i] # 如果我们手动传入了一个随机数方法 else: _int = int # 循环 len 次每次将索引为i的 值 和 索引为 一个小于i的随机整数 的值进行替换 for i in reversed(range(1, len(x))): # 通过我们手动传入的随机数方法的结果 * (i+1) 得到j的值 j = _int(random() * (i+1)) # 交换 索引为i 和索引为j的值 x[i], x[j] = x[j], x[i]
shuffle方法其实是不断进行两两索引位置的值进行交换 达到打乱顺序的
并且它是在原本的列表上进行打乱的,而没有新的列表生成
random.sample(self, population, k)
——返回从总体序列或集合中选择的唯一元素的k长度列表。用于无需更换的随机抽样。import random l = [1,2,3,4,5] l2 = random.sample(l,2) print(l2) [4, 3]
源码如下
def sample(self, population, k): # 判断population是否是可使用sample的类型(如果是set转成tuple 如果是tuple、list就继续运行 如果是dict直接报错) if isinstance(population, _Set): population = tuple(population) if not isinstance(population, _Sequence): raise TypeError("Population must be a sequence or set. For dicts, use list(d).") # self._randbelow 命名一个别名randbelow randbelow = self._randbelow # 计算population的长度 n = len(population) # 如果k >=n 或者<=0 就报错, k是选择元素的长度 if not 0 <= k <= n: raise ValueError("Sample larger than population or is negative") # 设置默认值 result = [None] * k setsize = 21 # 默认为小集合 # 如果k大于5则认为 是一个大集合 否则是小集合 if k > 5: setsize += 4 ** _ceil(_log(k * 3, 4)) # table size for big sets # 如果是小集合(An n-length list is smaller than a k-length set) if n <= setsize: # 将population强转成list pool = list(population) # 这里!!! 其实就是为了每次都可以选出列表中的一个数(选出一个之前没有选择过的数) 然后依次赋给result 这个之前设置的默认值为None 的列表 for i in range(k): # invariant: non-selected at [0,n-i) # 随机一个 n-i 的整数当作 下标赋给j j = randbelow(n-i) # 这下面两句就是在 把选中的数替换成倒置位的数 (因为倒置位的数一直无法取到所以将其替换到前面 ) result[i] = pool[j] # 将值赋给 result列表 pool[j] = pool[n-i-1] # move non-selected item into vacancy # 猜测是因为大集合如果转换成list太过于占空间 所以单独 拿了出来 else: # 创建了一个set 对象 selected = set() selected_add = selected.add # 给set对象的add方法 赋值一个别名 for i in range(k): j = randbelow(n) # 一个小于n的随机数 并赋给j 当作下标 # 如果j 不在selected中,即 我们没有选择过 下标为j的数,就跳过while循环 # 如果在selected中,即 我们曾经选择到 下标为j的数, 则重新取随机数 直到,选择一个从来没有使用过的j while j in selected: j = randbelow(n) selected_add(j) # 将j添加到集合中 result[i] = population[j] # 将值赋给 result列表 return result
簿记功能
random.seed(self, a=None, version=2)
——seed() 方法改变随机数生成器的种子,可以在调用其他随机模块函数之前调用此函数改变随机数生成器的种子seed。如果你不了解其原理,你不必特别去设定seed,Python会帮你选择seed。
import random random.seed(0) print(random.random()) random.seed(0) print(random.random())
0.8445167133186481 0.8445167133186481
源码如下
def seed(self, a=None, version=2): # a -- 改变随机数生成器的种子seed。如果你不了解其原理,你不必特别去设定seed,Python会帮你选择seed。 # 默认调用第二个方式 version = 2 # 是方案1 并且 a是str 或 bytes if version == 1 and isinstance(a, (str, bytes)): # 如果 a bed0 不为None 则 进行运算 否则x 为0 x = ord(a[0]) << 7 if a else 0 for c in a: x = ((1000003 * x) ^ ord(c)) & 0xFFFFFFFFFFFFFFFF x ^= len(a) a = -2 if x == -1 else x # 是方案2 并且 a是str 或 bytes 或 bytearray if version == 2 and isinstance(a, (str, bytes, bytearray)): # 如果a是字符串则 转成bytes类型 if isinstance(a, str): a = a.encode() # a 进行加密并进行拼接 a += _sha512(a).digest() a = int.from_bytes(a, 'big') # 调用父类的seed(父类中根据当前时间进行生成) super().seed(a) self.gauss_next = None
seed( ) 用于指定随机数生成时所用算法开始的整数值,如果使用相同的seed( )值,则每次生成的随即数都相同,如果不设置这个值,则系统根据时间来自己选择这个值,此时每次生成的随机数因时间差异而不同。
相关文章推荐
- day6 模块time datetime random os sys json pikle
- python random模块
- python的random模块及加权随机算法的python实现方法
- python中的random、shutil模块
- python random模块学习笔记
- python的random模块函数分析(一)
- Python random模块
- 【Python】区分python中random模块的randint与numpy.random模块的randint
- Python random模块
- python random模块整理
- python random模块整理
- Python 中的random模块
- 生成随机数模块random
- 使用random模块,生成动态随机密码 分类: python 小练习 python Module 2013-12-04 17:23 278人阅读 评论(0) 收藏
- python模块之random
- Python3之random模块
- python的random模块
- Python3 中 random模块
- python常用模块-random
- python中random模块基础用法(利用random生成验证码)