从给定字符生成固定长度随机字符串的最佳Python方法
这是我之前提问的一个延伸,具体可以查看我早期的问题
问题描述:给定一个数字N
和一个任意的(但不能为空的)集合
/字符串
/列表
,包含字符E
,要求返回一个由E
中的字符组成的随机字符串,长度为N
。
用Python最优雅的方式怎么做呢?我可以用''.join(( random.choice(E) for i in xrange(N) ))
,但我在寻找更好的方法。有没有random
或者itertools
中的内置函数可以做到这一点呢?
如果能做到以下几点会更好:
- 减少函数调用次数
- 能写成一行代码
- 对任意的
N
和E
都适用 - 运行效率更高
PS:我提这个问题其实是因为我对Python有点追求(如果我可以这么说的话),想找一些优雅和艺术感的代码写法。我提到这个是因为看起来有点像作业,我想向Stack Overflow社区保证这并不是作业。
2 个回答
4
你的解决方案看起来已经很不错了,不过为了全面起见,这里有一些其他的选择:
''.join(map(random.choice, [E]*N))
或者可以使用itertools库:
from itertools import repeat
''.join(map(random.choice, repeat(E, N)))
如果你在用Python 2.x,itertools.imap()
会比map()
更高效,因为它不会在内存中创建完整的列表。
这里有一些有趣的时间测试数据(在Python 2.6上测试的):
>>> import timeit
>>> t1 = timeit.Timer("''.join(random.choice('abcdefghijkl') for i in xrange(3))", "import random")
>>> t2 = timeit.Timer("''.join(map(random.choice, ['abcdefghijkl']*3))", "import random")
>>> t3 = timeit.Timer("''.join(map(random.choice, repeat('abcdefghijkl', 3)))", "import random; from itertools import repeat")
>>> t4 = timeit.Timer("''.join(random.sample('abcdefghijkl'*3, 3))", "import random")
>>> t1.timeit(1000000) # (random.choice(E) for i in xrange(N)) - OP
7.0744400024414062
>>> t2.timeit(1000000) # map(random.choice, [E]*N) - F.J
4.3570120334625244
>>> t3.timeit(1000000) # map(random.choice, repeat(E, N)) - F.J
5.9411048889160156
>>> t4.timeit(1000000) # random.sample(E*N, N) - DSM
6.9877378940582275
显然,map(random.choice, [E]*N)
是赢家,至少在小的E
和N
情况下是这样的。
9
''.join(random.sample(E*N, N))
虽然这样做在集合(sets)上可能不太管用,仔细想想。
''.join(random.choice(E) for i in xrange(N))
其实这已经相当符合Python的风格了——简单、清晰,而且表达得很好。
需要花几个小时去思考的那种“Python风格”其实并不是真正的Python风格。