10

我正在尝试编写一个 python 脚本来测试 /dev/random 的随机性,但我无法让它给我任何数字。我的代码看起来像这样

with open("/dev/random", 'rb') as file:
     print f.read(10)

我认为应该从 /dev/random 打印出 10 个字节,但它打印出的不是数字,而是奇怪的字符(非标准字母和无数字)。知道我做错了什么吗?

4

4 回答 4

16

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

于 2013-02-06T02:57:53.830 回答
9

您将获得 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)))
于 2013-02-06T03:12:20.970 回答
1

它正在打印随机字符,因此只需使用该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]

于 2013-02-06T03:11:45.977 回答
1

在 Python 3.2 及更高版本中,以下内容比旧答案中的解决方案更短且可能更快:

with open("/dev/random", 'rb') as f:
    print(int.from_bytes(f.read(10), 'big'))

这将打印一个 80 位数字(范围 0 到 2^80-1 包括在内)。

于 2017-05-19T15:36:22.963 回答