4、Python中的随机数:random模块初探 —— randint, choice, shuffle
说到随机数,很多人第一反应是「不就是抽奖嘛」。其实在编程里,随机数的水挺深的。我刚开始学Python时,觉得random模块就是个玩具,直到有一次做A/B测试,发现用户分组总是偏向某一方……嗯,从那以后我再也不敢小看它了。
这一章,咱们就聊聊Python的random模块。说白了,就是三个最常用的函数:randint、choice、shuffle。你想想看,这三个函数能覆盖多少场景?抽奖、洗牌、随机分组、数据采样……几乎所有的随机需求,它们都能搞定。
核心观点:随机数不是「乱来」,而是「有策略地乱来」。掌握这三个函数,你就掌握了Python随机操作的基本盘。
4.1 先导入再说:import random
Python的random模块是内置的,不需要额外安装。但有个坑——很多人直接写from random import *,我个人不建议这么做。为什么呢?因为random模块里有很多函数,万一你自定义的函数跟它重名了,调试起来很头疼。
我习惯这样写:
import random
# 或者只导入你需要的
from random import randint, choice, shuffle
这样代码可读性高,别人一看就知道你用了random里的东西。避坑指南:我曾经在项目里看到同事用from random import *,结果自己写了个sample()函数,直接把random的sample覆盖了……排查了半天。
4.2 randint:生成一个范围内的随机整数
randint(a, b),返回一个介于a和b之间的整数,包括两端。这是最常用的随机函数之一。
import random
# 模拟掷骰子
dice = random.randint(1, 6)
print(f"你掷出了 {dice} 点")
# 生成一个0到100之间的随机分数
score = random.randint(0, 100)
print(f"随机分数: {score}")
注意:randint是闭区间,也就是说randint(1, 6)可能返回1,也可能返回6。如果你想要半开区间[a, b),可以用randrange(a, b)。
小技巧:我在做验证码生成时,经常用randint配合字符串拼接。比如生成一个6位数字验证码:''.join(str(random.randint(0, 9)) for _ in range(6))。简单粗暴,但好用。
4.3 choice:从序列中随机选一个元素
choice(seq),从非空序列中随机返回一个元素。这个函数太实用了——抽奖、随机点名、随机选择题目……
import random
# 随机抽一个学生回答问题
students = ["张三", "李四", "王五", "赵六", "钱七"]
lucky_one = random.choice(students)
print(f"被点名的同学是: {lucky_one}")
# 随机选一个颜色
colors = ["红", "蓝", "绿", "黄", "紫"]
my_color = random.choice(colors)
print(f"今天穿 {my_color} 色")
这里有个细节:如果序列是空的,choice会抛出IndexError。所以用之前最好检查一下长度。
注意:choice每次只选一个。如果你想选多个且不重复,用sample;如果想选多个且可重复,用choices(注意是复数)。这三个函数容易搞混,我刚开始也经常写错。
4.4 shuffle:把序列的顺序打乱
shuffle(lst),原地打乱列表的顺序。注意,它直接修改原列表,不返回新列表。这个函数在洗牌、随机排序、数据增强等场景下非常有用。
import random
# 洗牌
cards = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"]
random.shuffle(cards)
print(f"洗牌后的顺序: {cards}")
# 随机排序学生名单
students = ["张三", "李四", "王五", "赵六"]
random.shuffle(students)
print(f"随机排序后: {students}")
避坑指南:shuffle只能用于可变序列(比如列表),不能用于元组或字符串。我曾经想打乱一个字符串,直接写了random.shuffle("hello"),结果报错了。正确的做法是转成列表再打乱:
s = "hello"
lst = list(s)
random.shuffle(lst)
shuffled = ''.join(lst)
print(shuffled) # 比如输出 "olleh"
4.5 三个函数的对比
这三个函数各有各的用途,我整理了一个表格,方便你对比:
| 函数 | 作用 | 返回值 | 是否修改原数据 | 典型场景 |
|---|---|---|---|---|
randint(a, b) |
生成[a, b]之间的随机整数 | 一个整数 | 否 | 掷骰子、生成验证码、随机分数 |
choice(seq) |
从序列中随机选一个元素 | 一个元素 | 否 | 抽奖、随机点名、随机选择 |
shuffle(lst) |
原地打乱列表顺序 | None(直接修改原列表) | 是 | 洗牌、随机排序、数据增强 |
4.6 综合案例:随机分组工具
光说不练假把式。咱们来写一个随机分组的小工具,把这三个函数都用上。
import random
def random_group(students, group_size):
"""
将学生随机分组,每组 group_size 人
"""
# 先打乱学生顺序
random.shuffle(students)
# 按组大小切分
groups = []
for i in range(0, len(students), group_size):
group = students[i:i + group_size]
groups.append(group)
return groups
# 测试
students = ["张三", "李四", "王五", "赵六", "钱七", "孙八", "周九", "吴十"]
groups = random_group(students, 3)
print("随机分组结果:")
for idx, group in enumerate(groups, 1):
print(f"第{idx}组: {', '.join(group)}")
这个例子中,shuffle负责打乱顺序,randint可以用来随机决定组的大小(如果你想的话),choice可以用来从每组中随机选一个组长。你看,三个函数配合起来,能做的事情就多了。
4.7 知识体系总览
下面这张图帮你梳理本章的核心知识点:
4.8 避坑总结
最后,我把常见的坑总结一下,这些都是我亲身踩过的:
- 不要用
random做密码学安全操作——它用的是伪随机数生成器,可预测。需要安全随机时用secrets模块。 shuffle是原地操作——如果你需要保留原列表,记得先复制一份:new_list = old_list[:],然后再打乱。choice的序列不能为空——用之前加个if seq:判断,避免程序崩溃。- 随机种子——如果你想让随机结果可复现(比如调试时),可以用
random.seed(42)固定种子。但生产环境一般不用。