在 Python 中想要隨機產生某數或抽籤功能可以使用 random
模組,這模組可以用來產生偽隨機數 (pseudo-random numbers),產生方式其實是用某種公式算出來的,至於為什麼不使用真隨機產生,可以參考這篇。
random module 不適合使用在安全性或加密用途
如果有此需求可以使用 secrets module
下面會針對隨機產生數字、隨機抽取出元素列出一些常用的方法
指定範圍內隨機產生一個整數
1. randrange(start, stop, step)
如果 start > stop 會發生 ValueError
;回傳值範圍為 start <= 回傳值 < stop 。
參數 | 敘述 | 預設值 |
---|---|---|
start | 指定隨機數範圍起點,選填。 | 0 |
stop | 指定隨機數範圍終點,必填。 | n/a |
step | 指定隨機抽取的間隔,選填。 | 1 |
import random # 務必要先引入
print(random.randrange(0, 5, 2)) # 可能出現 0, 2, 4 其ㄧ
print(random.randrange(1, 5)) # 可能出現 1, 2, 3, 4 其ㄧ
print(random.randrange(5)) # 可能出現 0, 1, 2, 3, 4 其ㄧ
2. randint(a, b)
如果 a > b 會發生 ValueError
,回傳值範圍為 a <= 回傳值 <= b ,有沒有覺得跟 randrange
很雷同,其實 randint
就是 randrange(a, b + 1)
的另一種寫法。
import random # 務必要先引入
print(random.randint(1, 5) # 可能出現 1, 2, 3, 4, 5 其ㄧ
print(random.randrange(1, 6) # 可能出現 1, 2, 3, 4, 5 其ㄧ
隨機產生一個浮點數
1. random()
會產生一個 0.0 ~ 1.0 之間的任一浮點數。
import random # 務必要先引入
print(random.random()) # 0.9016921451498453
2. uniform(a, b)
回傳值範圍為 a <= 回傳值 <= b。
import random # 務必要先引入
print(random.uniform(10, 50)) # 49.98014509364687
從序列隨機抽取
序列是元素的集合,如: string
、 List
、 Tuple
等,可針對序列做隨機相關的方法,這讓我想到以前數學課 C 幾取幾的東東。
1. choice(seq) 多選一
從序列中隨機取得一個元素,seq 為空會產生 IndexError
。
import random # 務必要先引入
print(random.choice(["一", "二", "三"])) # "二"
2. choices(population, k=n) 取後放回
從序列中隨機抽取 n 個元素,可重複抽取,會回傳 List
,population 為空會產生 IndexError
;另有參數可以配置權重,提高選中機率,細節可參見最後的參考資料。
import random # 務必要先引入
print(random.choices(["一", "二", "三", "四"], k=3)) # ["一", "三", "一"]
3. sample(population, k=n) 取後不放回
從序列中隨機抽取 n 個元素,不重複抽取,會回傳 List
,如果 n > len(population)
(樣本數 > 母體數) 會產生 ValueError
;有其他參數可提高選中機率,細節可參見最後的參考資料。
import random # 務必要先引入
print(random.sample(["一", "二", "三", "四"], k=3)) # ["一", "三", "四"]
4. shuffle(x) 隨機排序
將傳入的 list
原地 (in place) 打亂排序;若想保留原本的陣列,回傳一個新的打亂後 list
,可以使用 sample(x, k=len(x))
。
import random # 務必要先引入
my_list = ["一", "二", "三", "四"]
# shuffle 將傳入陣列原地隨機排序
random.shuffle(my_list)
print(my_list) # ["一", "三", "四", "二"]
# shuffle 不會回傳值
new_list = random.shuffle(my_list)
print(new_list) # None
# sample 可以回傳一個打亂後的新 list
ori_list = ["一", "二", "三", "四"]
new_list = random.sample(ori_list, k=len(ori_list))
print(ori_list) # ["一", "二", "三", "四"]
print(new_list) # ["三", "四", "二", "一"]
隨機結果再現
這部分我覺得有點難以想像,所以就舉 RPG 的例子來幫助理解。
1. seed(a) 指定章節開始
可以初始化亂數產生器,a 預設值為 None
,a = None
時會自動帶入當前的系統時間,可以指定 a 來獲得一樣的亂數值。
import random # 務必要先引入
# case A
random.seed(10)
print(random.random()) # 0.5714025946899135
print(random.random()) # 0.4288890546751146
# case B
random.seed(100)
print(random.random()) # 0.1456692551041303
# case C: 將 seed 設回 10,會得到跟 case A 一樣的結果
random.seed(10)
print(random.random()) # 0.5714025946899135
print(random.random()) # 0.4288890546751146
2. getstate()、setstate(state_obj) 接續進度
getstate() 存檔功能
會回傳一個產生器當前狀態的物件;如要恢復當初的狀態,要將物件傳遞給 setstate()
。
setstate(state_obj) 讀檔功能
傳入從 getstate()
得到的物件,可以恢復產生器在調用 getstate()
時的狀態。
import random # 務必要先引入
# 不初始化也可以透過 getstate、setstate 來獲得一致結果
# 只是產生的隨機數基本上會跟下面例子不一樣
random.seed(10)
# 將目前產生器狀態存檔
state = random.getstate()
print(random.random()) # 0.5714025946899135
print(random.random()) # 0.4288890546751146
# 讀檔以重現存檔時的狀態
random.setstate(state)
print(random.random()) # 0.5714025946899135
print(random.random()) # 0.4288890546751146