Skip to content

Instantly share code, notes, and snippets.

@zh4n7wm
Created May 4, 2019 08:58
Show Gist options
  • Select an option

  • Save zh4n7wm/0c93b95b5ee88332eb98c0a576248ddb to your computer and use it in GitHub Desktop.

Select an option

Save zh4n7wm/0c93b95b5ee88332eb98c0a576248ddb to your computer and use it in GitHub Desktop.
Python 产生随机字符串,尽可能保证唯一性

测试结论:

  • 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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment