
晚饭后,Tyree趴在沙发上看手机,突然喊起来:“快看快看!这个抽奖小程序,点一下按钮就随机抽一个人,好神奇!”
我凑过去看了一眼,说:“这用的是随机数。Python里也有一个专门干这个的模块,叫random。”
他立刻坐直了:“就是猜数字游戏里那个random.randint?”
“对,但它还能干更多事。比如随机点名、随机抽奖、随机洗牌……”
“那我能写一个随机点名器吗?下次我们班搞活动,我帮老师抽人。”他眼睛亮晶晶的。
我点头:“当然能,而且很简单。”
他兴奋地打开电脑,一边敲一边自言自语:“我要把全班同学的名字都输进去,然后让电脑随便抽一个……”
结果他第一次运行,就遇到了一个报错:IndexError: cannot choose from an empty list。
他愣了半天,说:“名字不是在里面吗?”我让他检查一下列表,发现他忘了把名字写进去,列表是空的。他不好意思地笑了:“如果电脑会读心术好了。”
后来我让他跟着我写了一个抽奖程序,奖品有“书包”“笔记本”“糖果”。
他想试试能不能连续抽到同一个奖品,结果用choices抽了10次,书包出现了4次,糖果只出现1次。他嘟囔:“这随机也太不公平了吧?”我告诉他,真正的随机就是这样,没有‘公平’,只有概率。
今天课程我们就来把random模块里这些有趣的函数一个个学会。从随机整数到随机选人,从抽奖到洗牌,再到生成密码。
学完之后,你也能做出各种“摇号”程序,还能理解为什么你抽卡总是抽不到SSR。
01
导入random模块
使用random之前,必须先导入它。
import random
这个我们前面已经有接触学过这个函数,就是随机猜数字游戏那里。
很多新手忘了写import random,运行时就会报错NameError: name 'random' is not defined,意思就是“我不知道random是什么”。
Tyree第一次就犯了这错,后来他每次写random之前都会先看一眼文件开头有没有import random。这就好比你要用锤子,得先从工具箱里拿出来。
02
随机整数:random.randint(a, b)
返回a到b之间的随机整数,包括a和b。

这是最常用的随机函数。猜数字游戏里的秘密数字就是用它生成的。
注意randint(1,10)有可能出1,也有可能出10,两头都包括。
如果你想要1到10但不要10,得用randrange(1,10)。
Tyree一开始以为randint(1,10)只到9,后来多跑了几次发现10也会出现,才搞明白。
03
随机小数:random.random() 和 random.uniform(a, b)
random.random() 返回0.0到1.0之间的随机小数(不包括1.0)。
random.uniform(a, b) 返回a到b之间的随机小数。
print(random.random()) # 比如 0.0598
print(random.uniform(5, 10)) # 比如 5.887

random.random() 最常用于做概率判断。
比如if random.random() < 0.3: 表示30%的概率执行某件事。游戏里“暴击率30%”就是这么写的。
Tyree拿它写了一个“抽卡模拟器”,30%的概率抽到SSR,他抽了20次,发现有时候连续出,有时候一直不出,他说:“原来随机不是平均分配,这就是运气啊。”
注意:random.random()永远不会等于1.0,所以严格来说<0.3就是30%概率。
04
从表中随机选一个:random.choice(列表)
这是Tyree最喜欢的函数,专门用来做抽奖和点名。
看下图

choice会在列表中随机挑一个元素。
要注意的是:如果列表是空的,会报错IndexError。所以用之前最好判断一下if students:(非空再抽)。
Tyree写随机点名器的时候,第一次运行就遇到了空列表报错,因为他忘了往列表里加名字。
后来让他加了一个判断:如果名单为空,就提示“请先添加学生”。

05
随机选多个(可重复):random.choices(列表, k=次数)
如果你想一次抽多个,比如抽3个幸运观众,用choices。注意:同一个元素可能被重复抽到。

k表示抽取几个。因为是“有放回”抽取(抽完一个人放回去,下次还可能抽到他),所以小明可能被抽两次。如果你想要“无放回”(抽过的不再抽),要用sample。
Tyree一开始用choices做抽奖,结果发现同一个人中了两次,他说这不公平。我说那你就用sample。他试了之后,搞定了。

06
随机选多个(不重复):random.sample(列表, k=次数)
sample 一次抽多个,且不会重复。抽奖、分组常用。

sample要求k不能大于列表长度,否则报错ValueError。比如你只有5个学生,却想抽6个不重复的,不可能。
Tyree写分组程序时,想从10个人里抽3个人一组,用sample正好。让他还加了一个判断:如果k > len(名单),就提示“人数不足”。

07
打乱列表顺序:random.shuffle(列表)
shuffle 会直接修改原列表,把顺序打乱。就像洗牌一样。

shuffle不会返回新列表,它是直接改原列表。很多新手会写成
new_cards= random.shuffle(cards),然后发现new_cards是None,因为shuffle没有返回值。
Tyree就被坑过,他说“为什么我的新列表是空的?”我告诉他,这就像你洗牌,牌还是在手里,只是顺序变了,不是变出了一副新牌。他恍然大悟。
08
小项目1:随机点名器(不重复点名)
写一个程序,每次运行随机点一名同学,并且不会重复点名,直到全部点完再重置。
看下图代码

这个程序用copy()复制了一份名单,然后用remove把点过的删掉。如果原列表很大,remove会慢一点,但几十个人没问题。
Tyree觉得这个程序很实用,他说老师每次点名都要看花名册,用这个直接随机抽,公平又好玩。
我让他还试着加了“跳过”功能(按s跳过当前同学,但不移出),用continue实现的。
09
小项目2:随机密码生成器
写一个程序,生成一个包含大小写字母、数字的随机密码,长度由用户指定。

这个程序用random.choice从字符池里随机抽,拼成密码。
平时真正的密码生成器还需要考虑特殊符号、避免容易混淆的字符(比如1和l),但这个版本够初学者用了。
Tyree生成了一堆密码,然后去问他爸哪个好记,他爸说都不好记,但安全。
10
今天学到了什么?
随机整数 random.randint(a,b) a到b之间,两头都算。
随机小数 random.random() 0到1之间的小数。
随机小数(范围)
random.uniform(a,b) a到b之间的小数。
随机选一个 random.choice(列表) 从列表里随便拿一个。
随机选多个(可重复)
random.choices(列表, k=n) 抽n次,每次独立,可能重复。
随机选多个(不重复)
random.sample(列表, k=n) 一次抽n个,不重复。
打乱顺序 random.shuffle(列表) 像洗牌一样,直接改原列表。
下一课我们将会学time模块——让程序学会“等待”和“计时”。
我们会学怎么让程序暂停几秒、计算代码运行时间、打印当前时间。用这个做一个“倒计时闹钟”,分分钟搞定,还可以给猜数字游戏加一个“限时挑战”模式。
————热门推荐————
自学编程第17课:变量的作用域——为什么函数里改不了外面的变量?
自学编程第8课:turtle画对称图形(彩色螺旋、彩色对称花、等边三角形、五角星)
自学编程第7课:turtle画图入门(画一个正方形,五角形,螺旋形,三角形)
自学编程第2课:用input让电脑问你名字(做一个打招呼程序)
自学编程第一步:安装Python和Thonny(零基础图文教程)
(本系列教程每天更新,欢迎关注收藏)