创建随机字符串和随机十六进制数的最轻量方式

125 投票
15 回答
146932 浏览
提问于 2025-04-15 22:25

怎样才能最简单地生成一个30个字符的随机字符串,比如下面这个?

ufhy3skj5nca0d2dfh9hwd2tbk9sw1

还有一个30位的十六进制数字,像下面这个?

8c6f78ac23b4a7b8c0182d7a89e9b1

15 个回答

94

30位十六进制字符串:

>>> import os
>>> os.urandom(15).hex()
"c84766ca4a3ce52c3602bbf02ad1f7"

这样做的好处是,它直接从操作系统获取随机数,这可能比random()方法更安全或者更快,而且你不需要手动设置种子。

95

在Python 3.6及以上版本中,还有一个新选择,就是使用标准的secrets模块:

生成随机的字母数字字符串:

In []:
import secrets
n = 30*3//4 # see note
secrets.token_urlsafe(n)

Out[]:
'teRq7IqhaRU0S3euX1ji9f58WzUkrg'

注意:token_urlsafe()使用的是base64编码,这意味着你需要把请求的数量减少3//4,才能得到确切的30。另外,你也可以把返回的字符串截取到前30个字符。
返回的字符串可能还会包含_-,不太清楚这样是否可以。

生成随机的十六进制字符串:

In []:
secrets.token_hex(15)

Out[]:
'8d9bad5b43259c6ee27d9aadc7b832'

时间记录:

In []:
%timeit secrets.token_urlsafe(n)

Out[]:
788 ns ± 4.32 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

In []:
%timeit secrets.token_hex(15)

Out[]:
631 ns ± 2.86 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
143

我这里有一个更快的方法来输出十六进制的结果。使用上面提到的同样的 t1t2

>>> t1 = timeit.Timer("''.join(random.choice('0123456789abcdef') for n in xrange(30))", "import random")
>>> t2 = timeit.Timer("binascii.b2a_hex(os.urandom(15))", "import os, binascii")
>>> t3 = timeit.Timer("'%030x' % random.randrange(16**30)", "import random")
>>> for t in t1, t2, t3:
...     t.timeit()
... 
28.165037870407104
9.0292739868164062
5.2836320400238037

t3 只需要调用一次随机模块,不用去创建或读取一个列表,然后就用字符串格式化来完成剩下的工作。

撰写回答