热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

python从源码讲解random模块(万字好文)

目录1.random.random()2.random.uniform()3.random.randrange()4.random.randint()5.random.c

目录

1.random.random()

2.random.uniform() 

3.random.randrange()

4.random.randint()

5.random.choice()

6.random.shuffle()

7.random.sample()



我们先来看一看random模块中有多少个方法

而此文章要讲解的方法主要有如下几个:


1.random.random()

2.random.uniform()

3.random.randrange()

4.random.randint()

5.random.choice()

6.random.shuffle()

7.random.sample()



1.random.random()

简介:


random.random()

作用:

用于生成一个0到1的随机浮点数

注意:

生成的浮点数的范围为0<&#61; n <1.0


源码&#xff1a;

def random(self):"""Get the next random number in the range [0.0, 1.0)."""return (int.from_bytes(_urandom(7), &#39;big&#39;) >> 3) * RECIP_BPF

这一句话是返回从区间[0,1)的随机浮点数

我们设计一段代码&#xff1a;

import random
if __name__ &#61;&#61; &#39;__main__&#39;:print(random.random())

控制台输出&#xff1a;

 

 


2.random.uniform() 


random.unifor(a, b)

作用&#xff1a;

用于生成一个指定范围内的随机符点数&#xff0c;两个参数其中一个是上限&#xff0c;一个是下限。

注意&#xff1a;

如果a > b&#xff0c;则生成的随机数n: b <&#61; n <&#61; a。如果 a

源码&#xff1a;

def uniform(self, a, b):"Get a random number in the range [a, b) or [a, b] depending on rounding."return a &#43; (b - a) * self.random()

我们发现这个方法有调用了random()方法&#xff0c;我们知道random()方法返回的是[0,1)的随机浮点数&#xff0c;那么uniform()方法&#xff0c;因为a不一定严格小于b,a也可能等于b&#xff0c;如果a&#61;b,那么返回的就是a&#xff0c;又因为a也可以大于b&#xff0c;所以返回值范围为[a,b]&#xff0c;为左闭右闭区间

我们设计一段代码&#xff1a;

import random
if __name__ &#61;&#61; &#39;__main__&#39;:print(random.uniform(2,4))

控制台输出&#xff1a;

 


3.random.randrange()

简介&#xff1a;


random.randrange(start, stop, step)

作用&#xff1a;

从指定范围内&#xff0c;按指定基数递增的集合中获取一个随机数

注意&#xff1a;

该方法返回的随机值是左闭右开的&#xff0c;也就是取不到stop的值

举例:

random.randrange(10, 30, 2)&#xff0c;结果相当于从[10, 12, 14, 16, ... 26, 28]序列中获取一个随机数。


查看源码&#xff1a;

def randrange(self, start, stop&#61;None, step&#61;1):"""Choose a random item from range(start, stop[, step]).This fixes the problem with randint() which includes theendpoint; in Python this is usually not what you want."""# This code is a bit messy to make it fast for the# common case while still doing adequate error checking.istart &#61; int(start)if istart !&#61; start:raise ValueError("non-integer arg 1 for randrange()")if stop is None:if istart > 0:return self._randbelow(istart)raise ValueError("empty range for randrange()")# stop argument supplied.istop &#61; int(stop)if istop !&#61; stop:raise ValueError("non-integer stop for randrange()")width &#61; istop - istartif step &#61;&#61; 1 and width > 0:return istart &#43; self._randbelow(width)if step &#61;&#61; 1:raise ValueError("empty range for randrange() (%d, %d, %d)" % (istart, istop, width))# Non-unit step argument supplied.istep &#61; int(step)if istep !&#61; step:raise ValueError("non-integer step for randrange()")if istep > 0:n &#61; (width &#43; istep - 1) // istepelif istep <0:n &#61; (width &#43; istep &#43; 1) // istepelse:raise ValueError("zero step for randrange()")if n <&#61; 0:raise ValueError("empty range for randrange()")return istart &#43; istep * self._randbelow(n)

我们几行代码几行代码的看。

 首先查看前几行代码&#xff1a;

istart &#61; int(start)
if istart !&#61; start:raise ValueError("non-integer arg 1 for randrange()")

这几行代码主要是对start进行处理。

我们现将传参进来的start转换为int类型&#xff0c;然后判断&#xff0c;如果istart不等于start&#xff0c;就抛出异常

我们来设计一段代码引出这个异常

import random
if __name__ &#61;&#61; &#39;__main__&#39;:print(random.randrange(1.1, 20, 2))

控制台输出&#xff1a;

因为我们start传参不是int类型的&#xff0c;所以就抛出了这个异常

接着查看这几行代码&#xff1a;

if stop is None:if istart > 0:return self._randbelow(istart)raise ValueError("empty range for randrange()")

 这几行代码对形参stop进行处理

如果形参stop为None&#xff0c;我们就对istart进行判断&#xff0c;如果istart大于0&#xff0c;返回self._randbelow(istart)&#xff0c;如果istart小于等于0&#xff0c;抛出异常

我们来设计一段代码来引出这个异常

import random
if __name__ &#61;&#61; &#39;__main__&#39;:print(random.randrange(0, None, 2))

控制台输出&#xff1a;

 关于self._randbelow(istart)是什么意思&#xff0c;我没有找到源码

于是我设计了一段代码

import random
if __name__ &#61;&#61; &#39;__main__&#39;:print(random.randrange(2, None, 1))

 发现只会出现两个结果&#xff0c;要么是0&#xff0c;要么是1&#xff0c;都是小于start且大于等于0的

所以_randbelow()方法返回的是小于该传入形参值的随机非负数&#xff0c;记住这个方法的作用&#xff0c;我们后面也会用到这个方法

我们接着看代码

istop &#61; int(stop)
if istop !&#61; stop:raise ValueError("non-integer stop for randrange()")

这段代码依然是对stop进行处理&#xff0c;和前面判断start一样&#xff0c;主要作用是为了防止传入的stop值有小数

我们接着看代码

width &#61; istop - istart
if step &#61;&#61; 1 and width > 0:return istart &#43; self._randbelow(width)
if step &#61;&#61; 1:raise ValueError("empty range for randrange() (%d, %d, %d)" % (istart, istop, width))

这几行代码是对step 和 width进行处理

1.如果step &#61;&#61; 1并且 width大于0&#xff0c;直接返回istart &#43; self._randbelow(width)&#xff0c;既然我们已经搞清楚_randbelow()方法的作用&#xff0c;那么这句话也就很好理解了&#xff0c;istart加上一个小于该序列长度的随机数。

设计一段代码&#xff1a;

import random
if __name__ &#61;&#61; &#39;__main__&#39;:print(random.randrange(1, 2, 1))

控制台输出&#xff1a;

  

在刚开始我们说randrange(start, stop, step)返回的随机数是[start,stop)左闭右开的&#xff0c;从这段代码我们就可以看出来&#xff0c;这段代码我们只能返回1。

假如我们start &#61; 1&#xff0c; stop &#61; 2&#xff0c;那么width &#61; 2 - 1 &#61; 1&#xff0c;而_randbelow(width)只会返回0这个数&#xff0c;那么istart&#43;self._randbelow(width)取到的值只有1这个数&#xff0c;不会取得2&#xff0c;所以说返回的随机数是左闭右开的。

2.如果step &#61;&#61; 1&#xff0c;这里后面的条件没有写&#xff0c;如果width 小于等于 0&#xff0c;那么就会继续抛出异常。

我们设计一段代码&#xff1a;

import random
if __name__ &#61;&#61; &#39;__main__&#39;:print(random.randrange(2, 2, 1))

控制台输出&#xff1a;

 我们接着看代码&#xff1a;

istep &#61; int(step)if istep !&#61; step:raise ValueError("non-integer step for randrange()")if istep > 0:n &#61; (width &#43; istep - 1) // istepelif istep <0:n &#61; (width &#43; istep &#43; 1) // istepelse:raise ValueError("zero step for randrange()")

这几行代码是对step进行处理

将step转换成int型&#xff0c;如果step不能与istep&#xff0c;那么就抛出异常&#xff0c; 前面对start和stop都是这么处理的&#xff0c;接着对istep进行判断

如果istep > 0&#xff0c;n &#61; (width &#43; istep - 1) // istep

如果istep <0&#xff0c;n &#61; (width &#43; istep &#43; 1) // istep

如果istep &#61; 0,抛出异常

我们设计一段抛出异常的代码&#xff1a;

import random
if __name__ &#61;&#61; &#39;__main__&#39;:print(random.randrange(2, 12, 0))

控制台输出&#xff1a; 

我们接着看代码

if n <&#61; 0:raise ValueError("empty range for randrange()")return istart &#43; istep * self._randbelow(n)

如果n<&#61;0&#xff0c;抛出异常&#xff0c;我们来设计代码实现这种情况

import random
if __name__ &#61;&#61; &#39;__main__&#39;:print(random.randrange(8, 8, 2))

控制台输出&#xff1a;

而如果n > 0&#xff0c;那么就返回istart &#43; istep * self._randbelow(n)

 这段代码通过和n值的巧妙结合&#xff0c;成功根据要求返回随机值&#xff0c;只能说设计这段代码的人确实厉害&#xff0c;我们举个例子

假如start &#61; 2,stop &#61; 10,step &#61; 2

计算width &#61; stop - start &#61; 8

n &#61; (width &#43; istep - 1) // istep &#61; (8 &#43; 2 - 1) // 2 &#61; 9 // 2 &#61; 4

那么最后返回的是istart &#43; istep * self._randbelow(n)

我们知道 self._randbelow(n)可以取得的值有0,1,2,3

那么返回的值就有2 &#43; 2 * {0,1,2,3}

2 &#43; 2 * 0 &#61; 2

2 &#43; 2 * 1 &#61; 4

2 &#43; 2 * 2 &#61; 6

2 &#43; 2 * 3 &#61; 8

取不到10&#xff0c;所以randrange(start, stop, step)返回的随机值是左闭右开的

设计代码&#xff1a;

import random
if __name__ &#61;&#61; &#39;__main__&#39;:print(random.randrange(2, 10, 2))

控制台输出&#xff1a;

自此&#xff0c;我们randrange()方法的源代码就看完了


4.random.randint()


random.randint(a, b)

作用&#xff1a;

用于生成一个指定范围内的整数。其中参数a是下限&#xff0c;参数b是上限

注意&#xff1a;

返回的随机数是左闭右闭的,即[a,b]

举例&#xff1a;

random.randint(2,6)&#xff0c;结果相当于从结果相当于从[2,3,4,5,6]序列中获取一个随机数。


查看源码&#xff1a;

def randint(self, a, b):"""Return random integer in range [a, b], including both end points."""return self.randrange(a, b&#43;1)

 看源码我们发现这个方法调用了randrange(a, b&#43;1)这个方法&#xff0c;上面我们已经讲过randrange()这个方法了&#xff0c;这里为了保证右边是闭区间&#xff0c;所以stop &#61; b &#43; 1

 


5.random.choice()

简介&#xff1a;


random.choice(sequence)

作用:

从序列中获取一个随机元素

注意&#xff1a;

sequence在python不是一种特定的类型&#xff0c;而是泛指一系列的类型。list, tuple, 字符串都属于sequence


 源码&#xff1a;

def choice(self, seq):"""Choose a random element from a non-empty sequence."""# raises IndexError if seq is emptyreturn seq[self._randbelow(len(seq))]

上面我们已经讲解了_randbelow()方法的作用&#xff0c;而这里_randbelow(len(seq))方法返回的是小于seq序列长度的随机数&#xff0c;最后返回的是序列中的一个随机元素。

我们设计一段代码&#xff1a;

import random
if __name__ &#61;&#61; &#39;__main__&#39;:lst &#61; [&#39;python&#39;, &#39;Java&#39;, &#39;C&#43;&#43;&#39;, &#39;Javascript&#39;]str &#61; (&#39;Hello,world!&#39;)print(random.choice(lst))print(random.choice(str))

控制台输出 &#xff1a;

 


6.random.shuffle()

简介&#xff1a;


random.shuffle(x[, random])

作用&#xff1a;

用于将一个列表中的元素打乱,即将列表内的元素随机排列


源码&#xff1a;

def shuffle(self, x, random&#61;None):"""Shuffle list x in place, and return None.Optional argument random is a 0-argument function returning arandom float in [0.0, 1.0); if it is the default None, thestandard random.random will be used."""if random is None:randbelow &#61; self._randbelowfor i in reversed(range(1, len(x))):# pick an element in x[:i&#43;1] with which to exchange x[i]j &#61; randbelow(i &#43; 1)x[i], x[j] &#61; x[j], x[i]else:_warn(&#39;The *random* parameter to shuffle() has been deprecated\n&#39;&#39;since Python 3.9 and will be removed in a subsequent &#39;&#39;version.&#39;,DeprecationWarning, 2)floor &#61; _floorfor i in reversed(range(1, len(x))):# pick an element in x[:i&#43;1] with which to exchange x[i]j &#61; floor(random() * (i &#43; 1))x[i], x[j] &#61; x[j], x[i]

 由于我还没有列表&#xff0c;这里就不先分析源码了

设计一段程序&#xff1a;

import random
if __name__ &#61;&#61; &#39;__main__&#39;:p &#61; [&#39;A&#39;, &#39;B&#39;, &#39;C&#39;, &#39;D&#39;, &#39;E&#39;]random.shuffle(p)print(p)

控制台输出&#xff1a;


7.random.sample()


random.sample(sequence, k)

作用&#xff1a;

从指定序列中随机获取指定长度的片断并随机排列。

注意&#xff1a;

sample函数不会修改原有序列。 


源码&#xff1a;

def sample(self, population, k, *, counts&#61;None):"""Chooses k unique random elements from a population sequence or set.Returns a new list containing elements from the population whileleaving the original population unchanged. The resulting list isin selection order so that all sub-slices will also be valid randomsamples. This allows raffle winners (the sample) to be partitionedinto grand prize and second place winners (the subslices).Members of the population need not be hashable or unique. If thepopulation contains repeats, then each occurrence is a possibleselection in the sample.Repeated elements can be specified one at a time or with the optionalcounts parameter. For example:sample([&#39;red&#39;, &#39;blue&#39;], counts&#61;[4, 2], k&#61;5)is equivalent to:sample([&#39;red&#39;, &#39;red&#39;, &#39;red&#39;, &#39;red&#39;, &#39;blue&#39;, &#39;blue&#39;], k&#61;5)To choose a sample from a range of integers, use range() for thepopulation argument. This is especially fast and space efficientfor sampling from a large population:sample(range(10000000), 60)"""# Sampling without replacement entails tracking either potential# selections (the pool) in a list or previous selections in a set.# When the number of selections is small compared to the# population, then tracking selections is efficient, requiring# only a small set and an occasional reselection. For# a larger number of selections, the pool tracking method is# preferred since the list takes less space than the# set and it doesn&#39;t suffer from frequent reselections.# The number of calls to _randbelow() is kept at or near k, the# theoretical minimum. This is important because running time# is dominated by _randbelow() and because it extracts the# least entropy from the underlying random number generators.# Memory requirements are kept to the smaller of a k-length# set or an n-length list.# There are other sampling algorithms that do not require# auxiliary memory, but they were rejected because they made# too many calls to _randbelow(), making them slower and# causing them to eat more entropy than necessary.if isinstance(population, _Set):_warn(&#39;Sampling from a set deprecated\n&#39;&#39;since Python 3.9 and will be removed in a subsequent version.&#39;,DeprecationWarning, 2)population &#61; tuple(population)if not isinstance(population, _Sequence):raise TypeError("Population must be a sequence. For dicts or sets, use sorted(d).")n &#61; len(population)if counts is not None:cum_counts &#61; list(_accumulate(counts))if len(cum_counts) !&#61; n:raise ValueError(&#39;The number of counts does not match the population&#39;)total &#61; cum_counts.pop()if not isinstance(total, int):raise TypeError(&#39;Counts must be integers&#39;)if total <&#61; 0:raise ValueError(&#39;Total of counts must be greater than zero&#39;)selections &#61; self.sample(range(total), k&#61;k)bisect &#61; _bisectreturn [population[bisect(cum_counts, s)] for s in selections]randbelow &#61; self._randbelowif not 0 <&#61; k <&#61; n:raise ValueError("Sample larger than population or is negative")result &#61; [None] * ksetsize &#61; 21 # size of a small set minus size of an empty listif k > 5:setsize &#43;&#61; 4 ** _ceil(_log(k * 3, 4)) # table size for big setsif n <&#61; setsize:# An n-length list is smaller than a k-length set.# Invariant: non-selected at pool[0 : n-i]pool &#61; list(population)for i in range(k):j &#61; randbelow(n - i)result[i] &#61; pool[j]pool[j] &#61; pool[n - i - 1] # move non-selected item into vacancyelse:selected &#61; set()selected_add &#61; selected.addfor i in range(k):j &#61; randbelow(n)while j in selected:j &#61; randbelow(n)selected_add(j)result[i] &#61; population[j]return result

同上&#xff0c;就不分析源码了&#xff0c;我们直接设计一段代码

import random
if __name__ &#61;&#61; &#39;__main__&#39;:p &#61; [&#39;A&#39;, &#39;B&#39;, &#39;C&#39;, &#39;D&#39;, &#39;E&#39;]print(random.sample(p,4))print(p)

控制台输出&#xff1a;

 


推荐阅读
author-avatar
暖暖252
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有