如何使用Python从/dev/random获取数字?
我正在尝试写一个Python脚本来测试/dev/random的随机性,但我无法得到任何数字。我的代码是这样的:
with open("/dev/random", 'rb') as file:
print f.read(10)
我认为这段代码应该能从/dev/random中打印出10个字节,但它却打印出一些奇怪的字符(不是标准字母,也没有数字)。你知道我哪里出错了吗?
4 个回答
它正在打印一些随机字符,所以只需要用 ord()
函数把它们转换成整数。可以这样做:
with open("/dev/random", 'rb') as file: print [ord(x) for x in file.read(10)]
这样就会打印出10个从0到255之间的随机整数。(我得到的是:[117, 211, 225, 24, 134, 145, 51, 234, 153, 89]
)。
你现在得到了10个字节。Python不会自动把它们变成数字。
我建议你每次抓取4个字节,然后把它们转换成32位的无符号整数,最后再根据需要进行缩放。
补充说明:之前的代码虽然展示了这个想法,但函数划分得不好。这里是相同的基本思路,不过现在把它们方便地整理成了函数。
import os
import struct
_random_source = open("/dev/random", "rb")
def random_bytes(len):
return _random_source.read(len)
def unpack_uint32(bytes):
tup = struct.unpack("I", bytes)
return tup[0]
UINT32_MAX = 0xffffffff
def randint(low, high):
"""
Return a random integer in the range [low, high], including
both endpoints.
"""
n = (high - low) + 1
assert n >= 1
scale_factor = n / float(UINT32_MAX + 1)
random_uint32 = unpack_uint32(random_bytes(4))
result = int(scale_factor * random_uint32) + low
return result
def randint_gen(low, high, count):
"""
Generator that yields random integers in the range [low, high],
including both endpoints.
"""
n = (high - low) + 1
assert n >= 1
scale_factor = n / float(UINT32_MAX + 1)
for _ in range(count):
random_uint32 = unpack_uint32(random_bytes(4))
result = int(scale_factor * random_uint32) + low
yield result
if __name__ == "__main__":
# roll 3 dice individually with randint()
result = [randint(1, 6) for _ in range(3)]
print(result)
# roll 3 dice more efficiently with randint_gen()
print(list(randint_gen(1, 6, 3)))
Python有一个内置的函数可以做到这一点(它在其他操作系统上也会使用合适的方法)...
import os
print os.urandom(10)
# '\xf1\x11xJOl\xab\xcc\xf0\xfd'
来自文档的说明,链接在这里:http://docs.python.org/2/library/os.html#os.urandom
这个函数会从操作系统特定的随机源返回随机字节。返回的数据应该足够不可预测,适合用在加密应用上,不过具体的质量还是要看操作系统的实现。在类UNIX系统上,它会查询/dev/urandom,而在Windows上,它会使用CryptGenRandom。如果找不到随机源,就会抛出一个NotImplementedError的错误。
如果你想把这些字节转换成数字,可以这样做:
>>> rand = os.urandom(10)
>>> int(binascii.hexlify(rand), 16)
1138412584848598544216317L
或者使用Python 2:
>>> int(rand.encode('hex'), 16)
1138412584848598544216317L
不过,/dev/random
和/dev/urandom
是有些不同的,所以如果这个区别对你来说很重要,你可以使用你现有的.read()
操作,然后进行int
转换。