如何生成一个大小为N的字符串,由数字和大写英文字母组成,例如:
- 6U1S75
- 4Z4UKK
- U911K4
如何生成一个大小为N的字符串,由数字和大写英文字母组成,例如:
Answer in one line:
''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(N))
甚至可以使用Python 3.6开始更短的方式,使用random.choices()
函数:
''.join(random.choices(string.ascii_uppercase + string.digits, k=N))
更具密码学安全性的版本: 请参阅此帖子
''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(N))
详细说明,包括一个可供进一步重用的清理函数:
>>> import string
>>> import random
>>> def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
... return ''.join(random.choice(chars) for _ in range(size))
...
>>> id_generator()
'G5G74W'
>>> id_generator(3, "6793YUIO")
'Y3U'
它是如何工作的?
我们导入 string
模块,该模块包含常见 ASCII 字符序列,并导入 random
模块,该模块处理随机生成。
string.ascii_uppercase + string.digits
仅仅是将表示大写 ASCII 字符和数字的字符列表连接起来:
>>> string.ascii_uppercase
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> string.digits
'0123456789'
>>> string.ascii_uppercase + string.digits
'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
然后,我们使用列表推导式创建一个包含'n'个元素的列表:
>>> range(4) # range create a list of 'n' numbers
[0, 1, 2, 3]
>>> ['elem' for _ in range(4)] # we use range to create 4 times 'elem'
['elem', 'elem', 'elem', 'elem']
[
创建列表,但在id_generator
函数中没有使用,因此Python不会在内存中创建列表,而是逐个生成元素(有关详细信息,请参见此处)。>>> random.choice("abcde")
'a'
>>> random.choice("abcde")
'd'
>>> random.choice("abcde")
'b'
random.choice(chars) for _ in range(size)
实际上创建了一个包含 size
个字符的序列,这些字符是从 chars
中随机选择的。>>> [random.choice('abcde') for _ in range(3)]
['a', 'b', 'b']
>>> [random.choice('abcde') for _ in range(3)]
['e', 'b', 'e']
>>> [random.choice('abcde') for _ in range(3)]
['d', 'a', 'c']
>>> ''.join(['a', 'b', 'b'])
'abb'
>>> [random.choice('abcde') for _ in range(3)]
['d', 'c', 'b']
>>> ''.join(random.choice('abcde') for _ in range(3))
'dac'
random
替换为 random.SystemRandom()
:https://github.com/django/django/blob/875ce287e25d7576f9bd102f86adae09d242360f/django/utils/crypto.py#L77 - userrandom.sample
创建的样本是不重复的,换句话说,没有重复字符的可能性,这并不符合OP的要求。我认为对于大多数应用程序来说这并不理想。 - ontologist这个Stack Overflow问题是“random string Python”的当前谷歌搜索结果中排名最高的。目前排名最高的答案是:
''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(N))
这是一个绝佳的方法,但是random库中的伪随机数生成器PRNG不具备加密安全性。我想很多研究这个问题的人都希望生成用于加密或密码的随机字符串。你可以通过对上述代码进行微小的更改来实现安全生成:
''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(N))
在需要安全的伪随机数生成器(PRNG)的应用程序中,使用random.choice
而不是random.SystemRandom().choice
可能会造成潜在的灾难性后果。使用random.SystemRandom()
代替普通的random
在*nix机器上使用/dev/urandom,在Windows上使用CryptGenRandom()
,都是具有密码学安全性的PRNGs。
如果您正在使用Python3.6或更高版本,则可以使用新的secrets模块,正如MSeifert的答案中提到的那样:
''.join(secrets.choice(string.ascii_uppercase + string.digits) for _ in range(N))
random
官方标准库已经发出警告: "警告:本模块的伪随机生成器不应用于安全目的。如果您需要加密安全的伪随机数生成器,请使用os.urandom()或SystemRandom。"
参考资料:random.SystemRandom和os.urandom - lord63. jstring.uppercase
,这可能会根据设置的语言环境导致意外结果。在涉及编码的情况下,使用string.ascii_uppercase
(或用于基于62进制的string.ascii_letters + string.digits
替代基于36进制的)更安全。 - Blixtxrange
而不是 range
,因为后者会生成一个内存列表,而前者则创建一个迭代器。 - Guyxrange
并不是一个小注释(除非这里的每个人都在使用Python 3=P)。我真的很困惑,为什么大多数这些示例都完全忽略了性能。另一件事就是不要在循环中连接字符串,这会产生巨大的差异。这段代码使用xrange
和只执行一次alphabet = string.ascii_uppercase + string.digits
可以使速度提高约20%(在笔记本电脑上使用time
进行了非常不科学的测试)。 - Marek Sapota如果UUID符合您的需求,请使用内置的uuid包。
import uuid; uuid.uuid4().hex.upper()[0:6]
示例:
import uuid
uuid.uuid4() #uuid4 => full random uuid
# Outputs something like: UUID('0172fc9a-1dac-4414-b88d-6b9a6feb91ea')
如果您需要确切的格式(例如,“6U1S75”),您可以像这样操作:
import uuid
def my_random_string(string_length=10):
"""Returns a random string of length string_length."""
random = str(uuid.uuid4()) # Convert UUID format to a Python string.
random = random.upper() # Make all characters uppercase.
random = random.replace("-","") # Remove the UUID '-'.
return random[0:string_length] # Return the random string.
print(my_random_string(6)) # For example, D9E50C
string_length
的大小不同,碰撞的可能性会成为一个问题。 - useros.urandom()
字节序列进行编码。这样可以跳过中间的 uuid
步骤,提高编码速度! - Martijn Pieters一种更简单、更快速但略微不太随机的方法是使用random.sample
而不是逐个选择每个字母。如果允许n次重复,则可以将您的随机基础扩大n倍,例如:
import random
import string
char_set = string.ascii_uppercase + string.digits
print ''.join(random.sample(char_set*6, 6))
注意:random.sample 避免字符重复,增大字符集的大小可以使多次重复变得可能,但是它们仍然比在纯随机选择中更不可能发生。如果我们选取长度为6的字符串,并将第一个字符选为 'X',在纯随机选择示例中,获得第二个字符为 'X' 的概率与获得第一个字符为 'X' 的概率相同。在 random.sample 实现中,获得任何后续字符为 'X' 的概率只有作为第一个字符时的6/7.sample
方法你永远不会得到重复的字符。当然,对于大于 36
的 N
值,这种方法会失败。 - bobinceimport uuid
lowercase_str = uuid.uuid4().hex
lowercase_str
是一个类似于 'cea8b32e00934aaea8c005a35d85a5c0'
的随机值。
uppercase_str = lowercase_str.upper()
uppercase_str
是 'CEA8B32E00934AAEA8C005A35D85A5C0'
uppercase_str[:N+1]
- Yajofrom secrets import choice
import string
''.join([choice(string.ascii_uppercase + string.digits) for _ in range(N)])
另外需要注意的是,使用列表推导式在使用str.join
时比使用生成器表达式更快!
更快、更简便、更灵活的方法是使用strgen
模块(pip install StringGenerator
)。
生成一个包含大写字母和数字的6位随机字符串:
>>> from strgen import StringGenerator as SG
>>> SG("[\u\d]{6}").render()
u'YZI2CI'
获取唯一列表:
>>> SG("[\l\d]{10}").render_list(5,unique=True)
[u'xqqtmi1pOk', u'zmkWdUr63O', u'PGaGcPHrX2', u'6RZiUbkk2i', u'j9eIeeWgEF']
保证字符串中有一个“特殊”字符:
>>> SG("[\l\d]{10}&[\p]").render()
u'jaYI0bcPG*0'
一个随机的HTML颜色:
>>> SG("#[\h]{6}").render()
u'#CEdFCa'
等等。
我们需要意识到这一点:
''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(N))
可能不包含数字(或大写字母)。
strgen
在开发时间上比以上任何解决方案更快。Ignacio 的解决方案是运行时性能最快的,并且使用 Python 标准库是正确的答案。但你几乎不会以那种形式使用它。你将想要使用 SystemRandom(如果不可用,则回退),确保所需的字符集已表示,使用 Unicode(或不使用),确保连续调用产生唯一的字符串,使用一个字符串模块字符类的子集等。所有这些都需要比提供的答案中的代码多得多。各种试图推广解决方案的尝试都有局限性,而 strgen 则使用简单的模板语言具有更大的简洁性和表达力来解决这些问题。
它在 PyPI 上:
pip install StringGenerator
声明:我是strgen模块的作者。
根据另一个 Stack Overflow 的回答,创建随机字符串和随机十六进制数的最轻量级方法,比被采纳的答案更好的版本是:
('%06x' % random.randrange(16**6)).upper()
更快速。
我觉得似乎还没有人回答这个问题呢,哈哈!但是,这里是我的回答:
import random
def random_alphanumeric(limit):
#ascii alphabet of all alphanumerals
r = (range(48, 58) + range(65, 91) + range(97, 123))
random.shuffle(r)
return reduce(lambda i, s: i + chr(s), r[:random.randint(0, len(r))], "")
如果你需要一个随机字符串而不是伪随机字符串,你应该使用os.urandom
作为源。
from os import urandom
from itertools import islice, imap, repeat
import string
def rand_string(length=5):
chars = set(string.ascii_uppercase + string.digits)
char_gen = (c for c in imap(urandom, repeat(1)) if c in chars)
return ''.join(islice(char_gen, None, length))
os.urandom
如何不是伪随机数?它可能使用更好的算法生成更随机的数字,但它仍然是伪随机的。 - Tyilo/dev/random
和/dev/urandom
之间的区别。问题在于当熵不足时,/dev/random
会阻塞,这限制了它的实用性。对于一次性密码本,/dev/urandom
并不够好,但我认为它比伪随机更好。 - John La Rooy/dev/random
和/dev/urandom
都是伪随机数生成器,但这可能取决于你的定义。 - Tyilo