如何使用Python从/dev/random获取数字?

12 投票
4 回答
15237 浏览
提问于 2025-04-17 14:54

我正在尝试写一个Python脚本来测试/dev/random的随机性,但我无法得到任何数字。我的代码是这样的:

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

我认为这段代码应该能从/dev/random中打印出10个字节,但它却打印出一些奇怪的字符(不是标准字母,也没有数字)。你知道我哪里出错了吗?

4 个回答

2

它正在打印一些随机字符,所以只需要用 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])。

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)))
21

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转换。

撰写回答