我正在尝试编写一个 python 脚本来测试 /dev/random 的随机性,但我无法让它给我任何数字。我的代码看起来像这样
with open("/dev/random", 'rb') as file:
print f.read(10)
我认为应该从 /dev/random 打印出 10 个字节,但它打印出的不是数字,而是奇怪的字符(非标准字母和无数字)。知道我做错了什么吗?
我正在尝试编写一个 python 脚本来测试 /dev/random 的随机性,但我无法让它给我任何数字。我的代码看起来像这样
with open("/dev/random", 'rb') as file:
print f.read(10)
我认为应该从 /dev/random 打印出 10 个字节,但它打印出的不是数字,而是奇怪的字符(非标准字母和无数字)。知道我做错了什么吗?
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
您将获得 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)))
它正在打印随机字符,因此只需使用该ord()
函数将它们转换为整数。就像是:
with open("/dev/random", 'rb') as file: print [ord(x) for x in file.read(10)]
这将打印从 0 到 255 的 10 个随机整数的列表。(我得到:)[117, 211, 225, 24, 134, 145, 51, 234, 153, 89]
。
在 Python 3.2 及更高版本中,以下内容比旧答案中的解决方案更短且可能更快:
with open("/dev/random", 'rb') as f:
print(int.from_bytes(f.read(10), 'big'))
这将打印一个 80 位数字(范围 0 到 2^80-1 包括在内)。