测试结论:
random_str = lambda length: ''.join(random.choice(letters) for x in range(length))产生的随机字符串当然是会出现重复的。- secrets.randbits 产生随机的 xx位的整数,然后将整数映射到字符串中,产生随机字符串 也是会重复的
- 两个重复的概率差不多(手动小范围测试,一次产生 100 组,每组一万个随机字符串;大概会有 4 个重复的)
- secrets.randbits的方法要比 random_str 快很多,大概两、三倍 (分别产生长度为 8、10的随机字符串测试)
secrets.randbits 生成随机字符串:
def urandom_str(length=8):
"""生成 大写字母 + 数字 的随机字符串,长度为 `length`
:param length: int, 随机字符串的长度
:return: str, 指定长度的随机字符串
"""
# 假设随机字符串长度为8:32 个字符 x 8 = 32 ** 8 = (2 ** 5) ** 8 = 2 ** 40
# 因此,bits = 5 * 随机字符串长度
bits = 5 * length
n = secrets.randbits(bits)
# string.digits + string.ascii_uppercase 去掉 '10IO',还剩 32 个字母
letters = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ'
encode_letters = {i: ch for (i, ch) in enumerate(letters)}
base = len(letters)
lst = []
while n > 0:
n, remainder = divmod(n, base)
lst.append(encode_letters[remainder])
return ''.join(lst)
测试两者的函数:
def benchmark(func, groups, size):
lst = []
while groups > 0:
lst.extend([func(8) for _ in range(size)])
groups -= 1
print(len(lst) - len(set(lst)))
重复个数测试:
benchmark(random_str, 200, 10000) # 4
benchmark(urandom_str, 200, 10000) # 4
速度测试:
[ins] In [26]: %timeit urandom_str(8)
9.61 µs ± 39.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
[nav] In [27]: %timeit random_str(8)
9.8 µs ± 84.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)