random模块
模块random包含生成伪随机数的函数,有助于编写模拟程序或生成随机输出的程序。请注意,虽然这些函数生成的数字好像是完全随机的,但它们背后的系统是可预测的。如果你要求真正的随机(如用于加密或实现与安全相关的功能),应考虑使用模块os中的函数urandom。模块random中的SystemRandom类基于的功能与urandom类似,可提供接近于真正随机的数据。
模块random中一些重要的函数
函 数 描 述
random() 返回一个0~1(含)的随机实数
getrandbits(n) 以长整数方式返回n个随机的二进制位
uniform(a, b) 返回一个a~b(含)的随机实数
randrange([start], stop, [step]) 从range(start, stop, step)中随机地选择一个数
choice(seq) 从序列seq中随机地选择一个元素
shuffle(seq[, random]) 就地打乱序列seq
sample(seq, n) 从序列seq中随机地选择n个值不同的元素
编写与统计相关的程序时,可使用其他类似于uniform的函数,它们返回按各种分布随机采集的数字,如贝塔分布、指数分布、高斯分布等。
来看几个使用模块random的示例。在这些示例中,我将使用前面介绍的模块time中的几个函数。首先,获取表示时间段(2016年)上限和下限的实数。为此,可使用时间元组来表示日期(将星期、儒略日和夏令时都设置为-1,让Python去计算它们的正确值),并对这些元组调用mktime:
from random import *
from time import *
date1 = (2016, 1, 1, 0, 0, 0, -1, -1, -1)
time1 = mktime(date1)
date2 = (2017, 1, 1, 0, 0, 0, -1, -1, -1)
time2 = mktime(date2)
接下来,以均匀的方式生成一个位于该范围内(不包括上限)的随机数:
>>> random_time = uniform(time1, time2)
然后,将这个数转换为易于理解的日期。
>>> print(asctime(localtime(random_time)))
Tue Aug 16 10:11:04 2016
在接下来的示例中,我们询问用户要掷多少个骰子、每个骰子有多少面。掷骰子的机制是使用randrange和for循环实现的。
from random import randrange
num = int(input('How many dice? '))
sides = int(input('How many sides per die? '))
sum = 0
for i in range(num): sum += randrange(sides) + 1
print('The result is', sum)
如果将这些代码放在一个脚本文件中并运行它,将看到类似于下面的交互过程:
How many dice? 3
How many sides per die? 6
The result is 10
现在假设你创建了一个文本文件,其中每行都包含一种运气情况(fortune),那么就可使用前面介绍的模块fileinput将这些情况放到一个列表中,再随机地选择一种。
# fortune.py
import fileinput, random
fortunes = list(fileinput.input())
print random.choice(fortunes)
在UNIX和macOS中,可使用标准字典文件/usr/share/dict/words来测试这个程序,这将获得一个随机的单词。
$ python fortune.py /usr/share/dict/words
dodge
来看最后一个示例。假设你要编写一个程序,在用户每次按回车键时都发给他一张牌。另外,你还要确保发给用户的每张牌都不同。为此,首先创建“一副牌”,也就是一个字符串列表。
>>> values = list(range(1, 11)) + 'Jack Queen King'.split()
>>> suits = 'diamonds clubs hearts spades'.split()
>>> deck = ['{} of {}'.format(v, s) for v in values for s in suits]
刚才创建的这副牌并不太适合玩游戏。我们来看看其中一些牌:
>>> from pprint import pprint
>>> pprint(deck[:12])
['1 of diamonds',
'1 of clubs',
'1 of hearts',
'1 of spades',
'2 of diamonds',
'2 of clubs',
'2 of hearts',
'2 of spades',
'3 of diamonds',
'3 of clubs',
'3 of hearts',
'3 of spades']
太有规律了,对吧?这个问题很容易修复。
>>> from random import shuffle
>>> shuffle(deck)
>>> pprint(deck[:12])
['3 of spades',
'2 of diamonds',
'5 of diamonds',
'6 of spades',
'8 of diamonds',
'1 of clubs',
'5 of hearts',
'Queen of diamonds',
'Queen of hearts',
'King of hearts',
'Jack of diamonds',
'Queen of clubs']
请注意,这里只打印了开头12张牌,旨在节省篇幅。如果你愿意,完全可以自己查看整副牌。
最后,要让Python在用户每次按回车键时都给他发一张牌,直到牌发完为止,只需创建一个简单的while循环。如果将创建整副牌的代码放在了一个程序文件中,那么只需在这个文件末尾添加如下代码即可:
while deck: input(deck.pop())
请注意,如果在交互式解释器中尝试运行这个while循环,那么每当你按回车键时都将打印一个空字符串。这是因为input返回你输入的内容(什么都没有),然后这些内容将被打印出来。在普通程序中,将忽略input返回的值。要在交互式解释器中也忽略input返回的值,只需将其赋给一个你不会再理会的变量,并将这个变量命名为ignore。