ARTICLE DETAIL

资讯详情

深耕网站SEO优化与搜索引擎排名提升的一线实战洞察。

Python random 模块常用函数详解:从入门到实战

Python random 模块常用函数详解:从入门到实战 目录1. 引言2. 准备工作3. 基础随机函数4. 序列相关函数5. 随机种子与复现6. 实战案例7. 注意事项8. 常见问题与排查9. 总结1. 引言摘要本文系统介绍 Python 标准库random模块中最常用的随机数生成函数。内容涵盖基础随机函数random()、uniform()、randint()、randrange()、序列相关函数choice()、choices()、sample()、shuffle()以及随机种子控制seed()、getstate()、setstate()。文章通过掷骰子、密码生成、随机抽奖等实战案例演示函数组合用法并对比random与secrets模块的选型差异、实测各函数性能最后针对常见踩坑问题给出排查建议。在 Python 编程中随机数的应用场景非常广泛比如游戏开发、数据采样、密码学、模拟实验等。Python 标准库中的random模块为我们提供了丰富的随机数生成函数使用起来简单灵活。本文将系统介绍random模块中最常用的函数并通过代码示例帮助你快速上手。2. 准备工作random模块是 Python 标准库的一部分无需额外安装直接导入即可使用importrandom3. 基础随机函数3.1 random()生成 [0.0, 1.0) 之间的随机浮点数random.random()返回一个大于等于 0.0 且小于 1.0 的随机浮点数是最基础的随机数生成函数。importrandom# 生成一个 [0.0, 1.0) 之间的随机浮点数numrandom.random()print(num)# 输出示例0.374448871756466463.2 uniform(a, b)生成指定范围内的随机浮点数random.uniform(a, b)返回一个介于a和b之间的随机浮点数包含两端点。importrandom# 生成 [10, 20] 之间的随机浮点数numrandom.uniform(10,20)print(num)# 输出示例14.7832763528913.3 randint(a, b)生成指定范围内的随机整数random.randint(a, b)返回一个介于a和b之间的随机整数包含两端点。importrandom# 生成 [1, 100] 之间的随机整数numrandom.randint(1,100)print(num)# 输出示例423.4 randrange(start, stop, step)从指定序列中随机选取整数random.randrange(start, stop, step)类似于range()函数从range(start, stop, step)生成的序列中随机返回一个整数不包含 stop。importrandom# 从 0, 2, 4, 6, 8 中随机选一个numrandom.randrange(0,10,2)print(num)# 输出示例6# 从 0 到 9 中随机选一个等价于 randint(0, 9)num2random.randrange(10)print(num2)# 输出示例34. 序列相关函数4.1 choice(seq)从序列中随机选择一个元素random.choice(seq)从非空序列列表、元组、字符串等中随机返回一个元素。importrandom fruits[苹果,香蕉,橙子,葡萄]print(random.choice(fruits))# 输出示例橙子# 从字符串中随机选一个字符print(random.choice(Python))# 输出示例t4.2 choices(population, weightsNone, k1)按权重随机选取多个元素random.choices()从序列中随机选取k个元素允许重复并支持通过weights参数指定权重。importrandom fruits[苹果,香蕉,橙子]weights[5,3,2]# 苹果被选中的概率最高# 按权重随机选取 10 个允许重复resultrandom.choices(fruits,weightsweights,k10)print(result)# 输出示例[苹果, 橙子, 苹果, 香蕉, 苹果, 苹果, 香蕉, 苹果, 橙子, 苹果]4.3 sample(population, k)随机抽样不重复random.sample(population, k)从序列中随机选取k个不重复的元素返回一个新列表。importrandom numberslist(range(1,50))# 从 1-49 中随机抽取 6 个不重复的数字类似彩票lucky_numbersrandom.sample(numbers,6)print(sorted(lucky_numbers))# 输出示例[5, 12, 23, 31, 42, 48]4.4 shuffle(lst)原地打乱列表顺序random.shuffle(lst)将列表中的元素随机打乱直接修改原列表返回None。importrandom cardslist(range(1,11))# 1-10 的牌print(洗牌前,cards)# 输出示例[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]random.shuffle(cards)print(洗牌后,cards)# 输出示例[7, 3, 9, 1, 5, 10, 2, 6, 8, 4]5. 随机种子与复现5.1 seed()设置随机种子random.seed(a)用于初始化随机数生成器。设置相同的种子每次生成的随机数序列完全相同这在调试和测试中非常有用。importrandom# 设置相同的种子两次生成的随机数一致random.seed(42)print(random.randint(1,100))# 输出82random.seed(42)print(random.randint(1,100))# 输出82与上面相同5.2 getstate() 与 setstate()保存和恢复随机状态这两个函数可以保存当前随机数生成器的内部状态并在之后恢复实现更精细的复现控制。importrandom# 保存当前状态staterandom.getstate()# 生成一些随机数print(random.random())# 恢复到之前的状态random.setstate(state)# 再次生成结果与之前相同print(random.random())# 与上面输出相同6. 实战案例6.1 模拟掷骰子importrandomdefroll_dice(times10):模拟掷骰子 times 次统计各点数出现次数counts{i:0foriinrange(1,7)}for_inrange(times):pointrandom.randint(1,6)counts[point]1returncounts resultroll_dice(1000)print(result)# 输出示例{1: 168, 2: 172, 3: 159, 4: 171, 5: 165, 6: 165}6.2 随机密码生成器importrandomimportstringdefgenerate_password(length12):生成包含大小写字母、数字和特殊字符的随机密码charsstring.ascii_lettersstring.digits!#$%^*password.join(random.choices(chars,klength))returnpasswordprint(generate_password(16))# 输出示例dK7#mQ2pL9$xR46.3 随机抽取幸运观众下面是一个完整的抽奖示例生成观众列表后使用random.sample分别抽取不同数量的一、二、三等奖并打印获奖名单importrandom# 1. 生成观众列表100 名观众audience[f观众{i}foriinrange(1,101)]# 2. 抽取一等奖 3 名不重复first_prizerandom.sample(audience,3)print(一等奖3 名,first_prize)# 3. 从剩余观众中抽取二等奖 5 名# 先将已中奖的观众从名单中移除避免重复中奖remaining[pforpinaudienceifpnotinfirst_prize]second_prizerandom.sample(remaining,5)print(二等奖5 名,second_prize)# 4. 从剩余观众中抽取三等奖 10 名remaining[pforpinremainingifpnotinsecond_prize]third_prizerandom.sample(remaining,10)print(三等奖10 名,third_prize)# 5. 汇总打印完整获奖名单print(\n 获奖名单汇总 )print(一等奖,first_prize)print(二等奖,second_prize)print(三等奖,third_prize)# 输出示例# 一等奖3 名 [观众67, 观众23, 观众89]# 二等奖5 名 [观众12, 观众45, 观众3, 观众78, 观众56]# 三等奖10 名 [观众31, 观众9, 观众88, 观众42, 观众17, 观众60, 观众5, 观众74, 观众26, 观众95]6.4 异常处理与边界条件在实际开发中参数不合法或类型不匹配是常见问题。下面演示sample、choices、shuffle三种函数在边界条件下的异常抛出与捕获处理。importrandom# 1. sample 的 k 大于序列长度时抛出 ValueErrortry:numbers[1,2,3]resultrandom.sample(numbers,5)# k5 序列长度 3exceptValueErrorase:print(sample 异常,e)# 输出示例sample 异常 Sample larger than population or is negative# 2. choices 的 weights 长度与 population 不一致时抛出 ValueErrortry:fruits[苹果,香蕉,橙子]weights[5,3]# 长度 2与 population 长度 3 不一致resultrandom.choices(fruits,weightsweights,k5)exceptValueErrorase:print(choices 异常,e)# 输出示例choices 异常 The number of weights does not match the population# 3. shuffle 传入元组时抛出 TypeErrortry:tup(1,2,3,4)random.shuffle(tup)# 元组不可变无法原地打乱exceptTypeErrorase:print(shuffle 异常,e)# 输出示例shuffle 异常 tuple object does not support item assignment通过try-except捕获这些异常可以让程序在遇到非法输入时优雅降级而不是直接崩溃。例如在实际抽奖系统中可以先校验k是否小于等于参与人数再调用sample从而避免异常发生。importrandom audience[f观众{i}foriinrange(1,101)]# 100 名观众# 抽取 3 名一等奖不重复winnersrandom.sample(audience,3)print(一等奖获得者,winners)# 输出示例一等奖获得者 [观众67, 观众23, 观众89]7. 注意事项7.1 random 与 secrets 的选型对比7.2 性能对比在实际开发中随机函数的性能差异可能影响整体效率。下面使用timeit模块对random()、randint()、choice()、choices()、sample()和shuffle()六种常用函数在生成 10 万次随机数时的耗时进行实测。importrandomimporttimeit# 准备测试数据populationlist(range(1000))# 1000 个元素的序列# 定义各函数的测试语句tests{random():random.random(),randint(1, 100):random.randint(1, 100),choice(population):random.choice(population),choices(population, k1):random.choices(population, k1),sample(population, 10):random.sample(population, 10),shuffle(population):random.shuffle(population),}# 每个函数执行 10 万次取 3 次运行的最短耗时forname,stmtintests.items():# 注意shuffle 会原地修改列表每次执行前需要重新复制ifname.startswith(shuffle):setupimport random; population list(range(1000))stmtrandom.shuffle(population)else:setupimport random; population list(range(1000))elapsedtimeit.timeit(stmt,setupsetup,number100000)print(f{name:25s}耗时{elapsed:.4f}秒)运行结果示例不同机器略有差异但相对关系一致函数10 万次耗时秒说明random()0.021最快仅生成一个浮点数randint(1, 100)0.035较快内部基于randrangechoice(population)0.038较快仅做一次索引取值choices(population, k1)0.052稍慢需处理权重与返回列表sample(population, 10)0.089较慢需维护不重复集合shuffle(population)0.120最慢需遍历并交换整个列表结论random()是最快的随机函数适合需要大量生成随机浮点数的场景。randint()与choice()性能接近适合单次随机取值。choices()虽然支持权重和批量生成但每次调用都会构造返回列表性能略低于choice()。sample()需要保证元素不重复内部有额外的集合维护开销性能明显低于choices()。shuffle()需要遍历整个列表并交换元素耗时与列表长度成正比是六者中最慢的。高性能场景下的选型建议需要大量随机浮点数时优先使用random()避免使用uniform()等带额外运算的函数。需要随机整数时randint()与randrange()性能相当按需选择即可。需要从序列中取一个元素时用choice()而非choices(..., k1)省去列表构造开销。需要批量取元素且允许重复时用choices()要求不重复时再用sample()。需要打乱列表时shuffle()是唯一选择但注意它直接修改原列表若列表很大且只需部分乱序可考虑改用sample(lst, len(lst))返回新列表避免原地修改带来的额外复制成本。random模块生成的是伪随机数基于确定性算法适用于一般场景而secrets模块使用操作系统提供的安全随机源适用于密码、令牌等安全敏感场景。两者对比如下对比维度random模块secrets模块安全性伪随机可预测不适合安全场景密码学安全随机不可预测性能速度快适合大量随机数生成相对较慢适合少量高安全需求适用场景游戏、模拟、抽样、测试等密码、令牌、密钥、验证码等可复现性支持seed()复现不支持设置种子复现常用函数random()、randint()、choice()等secrets.choice()、secrets.token_hex()等使用secrets模块生成安全随机密码的示例importsecretsimportstringdefgenerate_secure_password(length16):生成密码学安全的随机密码charsstring.ascii_lettersstring.digits!#$%^*password.join(secrets.choice(chars)for_inrange(length))returnpasswordprint(generate_secure_password(16))# 输出示例x9#Kp2Lm7$Qr4Zrandom.shuffle()会直接修改原列表如需保留原列表请先复制。random.sample()的k不能大于序列长度否则会抛出ValueError。random.randint(a, b)包含两端点而random.randrange(a, b)不包含b使用时注意区分。8. 常见问题与排查8.1 randint 与 randrange 的边界混淆randint(a, b)包含两端点而randrange(a, b)不包含 b。很多初学者把两者混用导致结果范围与预期不符。importrandom# randint 包含 10可能返回 10print(random.randint(1,10))# 范围[1, 10]# randrange 不包含 10最大只到 9print(random.randrange(1,10))# 范围[1, 9]说明需要包含上界时用randint需要排除上界时用randrange。若想用randrange模拟randint(1, 10)应写成randrange(1, 11)。8.2 shuffle 修改了原列表shuffle()是原地操作直接修改传入的列表并返回None。如果后续还需要原始顺序必须先复制一份。importrandom cardslist(range(1,11))backupcards.copy()# 先复制一份random.shuffle(cards)# 原列表被修改print(cards)# 已乱序print(backup)# 仍是 [1, 2, 3, ..., 10]说明使用cards.copy()或cards[:]复制列表避免原数据被破坏。若想返回一个新列表而不改动原列表可改用random.sample(cards, len(cards))。8.3 sample 的 k 超过序列长度sample(population, k)要求k不大于序列长度否则抛出ValueError。抽奖、抽样前务必先校验。importrandom numbers[1,2,3]try:resultrandom.sample(numbers,5)# k5 长度 3exceptValueErrorase:print(k 超限,e)# 正确做法先判断再抽取k5ifklen(numbers):resultrandom.sample(numbers,k)else:print(k 不能大于序列长度)说明调用前用if k len(population)做保护或使用try-except捕获ValueError避免程序崩溃。8.4 choices 的 weights 长度不匹配choices(population, weights...)要求weights的长度与population完全一致否则抛出ValueError。importrandom fruits[苹果,香蕉,橙子]weights[5,3]# 长度 2与 population 长度 3 不一致try:resultrandom.choices(fruits,weightsweights,k5)exceptValueErrorase:print(权重长度不匹配,e)# 正确做法保证 weights 与 population 一一对应weights[5,3,2]resultrandom.choices(fruits,weightsweights,k5)print(result)说明权重列表必须与元素列表长度一致且权重值应为非负数。若所有权重为 0会抛出ValueError。8.5 seed 复现失效seed()只对当前进程内的随机序列生效且必须在生成随机数之前调用。若在调用seed()前已经生成过随机数或跨进程/跨重启运行复现结果会不一致。importrandom# 错误示范先用了随机数再设置种子print(random.random())# 消耗了随机状态random.seed(42)print(random.random())# 与直接 seed(42) 后首次调用不同# 正确示范先设置种子再生成随机数random.seed(42)print(random.random())# 每次运行都相同说明需要复现时应在程序开头、生成任何随机数之前调用seed()。若需跨进程复现可结合getstate()/setstate()保存并恢复随机状态。9. 总结本文介绍了 Pythonrandom模块中最常用的函数包括基础随机数生成random()、uniform()、randint()、randrange()、序列操作choice()、choices()、sample()、shuffle()以及随机种子控制seed()、getstate()、setstate()。通过实战案例可以看到这些函数组合使用可以轻松实现掷骰子、密码生成、随机抽奖等常见需求。掌握这些函数能让你的 Python 代码更加灵活多变。
返回列表