我对 random.random() 函数在 python 中的工作方式有点困惑。
的文档说,它的回归在[0.0,1.0)的范围内的下一个随机浮点数'。我知道伪随机数生成器通过对值执行一些操作来工作。通常,此值是生成器生成的前一个数字。所以我认为这就是“下一个随机浮点”在这里的意思。(如果我错了,请纠正我)
但是当我看到随机库的源代码时,在class Random. 相反,它的定义class SystemRandom如下(代码的第 671 行):
def random(self):
"""Get the next random number in the range [0.0, 1.0)."""
return (int.from_bytes(_urandom(7), 'big') >> 3) * RECIP_BPF
Run Code Online (Sandbox Code Playgroud)
如果我理解正确,这个函数会使用 os.urandom 生成一个随机数。根据文档,其中从特定于操作系统的随机性源返回随机字节。所以这不会给出“下一个”浮点随机数。
两者是如何联系起来的?或者它们是两种不同的东西?
我在这里很困惑。任何形式的帮助将不胜感激。
谢谢!
Bla*_*ere 13
randompython中的模块包含伪随机数生成器(PRNG)的两个接口(类)。您可以将其视为生成随机数的两种方式。
关于模块的说明
secrets。该模块
secrets并没有实现任何类型的PRNG基于SystemRandom和os.urandom(其中SystemRandom基于),但提供了辅助功能(这是真棒,因为我们没有写他们自己)。评论是我的:Run Code Online (Sandbox Code Playgroud)from random import SystemRandom _sysrand = SystemRandom() #secrets._sysrand randbits = _sysrand.getrandbits #secrets.randbits choice = _sysrand.choice #secrets.choice def randbelow(exclusive_upper_bound): #secrets.randbelow ... return _sysrand._randbelow(exclusive_upper_bound) #uses SystemRandom def token_bytes(nbytes=None): #secrets.token_bytes ... return os.urandom(nbytes) def token_hex(nbytes=None): #secrets.token_hex(uses token_bytes()) ... return binascii.hexlify(token_bytes(nbytes)).decode('ascii') def token_urlsafe(nbytes=None): # secrets.token_urlsafe(uses token_bytes()) ... tok = token_bytes(nbytes) return base64.urlsafe_b64encode(tok).rstrip(b'=').decode('ascii')
random.random() 在第 749 行的“random.py”模块中定义(对我而言)
_inst = Random()
...
random = _inst.random
Run Code Online (Sandbox Code Playgroud)
该类random.Random()本身并不定义random()方法,而是继承_random.Random()(它定义了一个名为 的方法random()),这是一个Random()位于模块 中的类_random。
(它是一个内置模块)模块的C源代码_random可以在这里找到(它实际上被称为_randommodule.c。见下面的解释)
用 C/C++ 编写的 python 模块的命名约定
(历史上,如果一个模块被称为 spam,包含其实现的 C 文件被称为 spammodule.c;如果模块名称很长,如 spammify,模块名称可以只是 spammify.c。)
的_random.Random.random()(或random.random())方法被定义为_random_Random_random_impl()中_randommodule.c文件。
static PyObject *
_random_Random_random_impl(RandomObject *self)
{
uint32_t a=genrand_int32(self)>>5, b=genrand_int32(self)>>6;
return PyFloat_FromDouble((a*67108864.0+b)*(1.0/9007199254740992.0));
}
Run Code Online (Sandbox Code Playgroud)
genrand_int32()是由Mersenne Twister PRNG实现定义的函数,它返回一个 4 字节的数字。
(我知道你没有要求 SystemRandom(),但在我写这篇文章的时候我还没有意识到)
我已经制作了这张图片作为我的答案的概述(但是,我鼓励您阅读所有内容)
SystemRandom().random()在模块中定义random.py。
...
def random(self):
"""Get the next random number in the range [0.0, 1.0)."""
return (int.from_bytes(_urandom(7), 'big') >> 3) * RECIP_BPF**strong text**
Run Code Online (Sandbox Code Playgroud)
该函数使用模块中定义的另一个名为 urandom() 的函数 os.py
from os import urandom as _urandom
Run Code Online (Sandbox Code Playgroud)
该os.py模块不定义函数urandom()本身,而是从内置模块中导入它。os.py将导入的posix,如果你是一个内置的模块 POSIX OS或nt内置模块,如果你是一个Windows NT的操作系统。这些模块包含 urandom() 的定义。
if 'posix' in _names:
name = 'posix'
linesep = '\n'
from posix import *
Run Code Online (Sandbox Code Playgroud)
或者
elif 'nt' in _names:
name = 'nt'
linesep = '\r\n'
from nt import *
Run Code Online (Sandbox Code Playgroud)
posix并且nt是内置模块,因此它们没有该__file__属性。
urandom()在调用_PyOS_URandom()的posixmodule.cas os_urandom_impl() 中定义。
static PyObject *
os_urandom_impl(PyObject *module, Py_ssize_t size)
{
...
bytes = PyBytes_FromStringAndSize(NULL, size);
...
result = _PyOS_URandom(PyBytes_AS_STRING(bytes), PyBytes_GET_SIZE(bytes));
...
return bytes
}
Run Code Online (Sandbox Code Playgroud)
_PyOS_URandom()在bootstrap_hash.c文件中定义,然后调用pyurandom()
int
_PyOS_URandom(void *buffer, Py_ssize_t size)
{
return pyurandom(buffer, size, 1, 1);
}
Run Code Online (Sandbox Code Playgroud)
pyurandom()在bootstrap_hash.c文件中定义,然后调用dev_urandom()。
static int
pyurandom(void *buffer, Py_ssize_t size, int blocking, int raise)
{
...
return dev_urandom(buffer, size, raise);
...
}
Run Code Online (Sandbox Code Playgroud)
dev_urandom在bootstrap_hash.c文件中定义,然后使用该/dev/urandom目录来获取随机字节。
static int
dev_urandom(char *buffer, Py_ssize_t size, int raise)
{
...
fd = _Py_open("/dev/urandom", O_RDONLY);
...
do {
n = _Py_read(fd, buffer, (size_t)size);
...
} while (0 < size);
...
}
Run Code Online (Sandbox Code Playgroud)
它可能看起来有点奇怪(我也这么认为)但该
posixmodule.c文件也用于 NT 系统,这里是文件开头的引用(评论)此文件也用于 Windows NT/MS-Win。在这种情况下,
模块实际上称自己为“nt”,而不是“posix”,并且一些函数要么未实现,要么以不同方式实现。源代码
假定对于 Windows NT,宏“MS_WINDOWS”的定义与所使用的编译器无关。不同的编译器定义了它们自己的功能测试宏,例如'_MSC_VER'。
对于 Windows NT,函数调用链与 POSIX 相同,直到 pyurandom() 函数
pyurandom()在bootstrap_hash.c文件中定义,然后调用win32_urandom()。
static int
pyurandom(void *buffer, Py_ssize_t size, int blocking, int raise)
{
...
#ifdef MS_WINDOWS
return win32_urandom((unsigned char *)buffer, size, raise);
#else
...
}
Run Code Online (Sandbox Code Playgroud)
win32_urandom()在bootstrap_hash.c文件中定义,然后调用CryptGenRandom().
static int
win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise)
{
...
if (!CryptGenRandom(hCryptProv, chunk, buffer))
{
...
}
...
return 0;
}
Run Code Online (Sandbox Code Playgroud)
CryptGenRandom()在wincrypt.h文件中声明并在Advapi32.lib和Advapi32.dll库中定义(这些文件由 Microsoft 提供)
random.random()实际上在这里定义:
random = _inst.random
Run Code Online (Sandbox Code Playgroud)
但是,它只是对 C 实现的引用。
这是来自源的引用:
关于底层 Mersenne Twister 核心生成器的一般说明:
- 周期为2**19937-1。
- 它是现有测试最广泛的发电机之一。
- random() 方法是用 C 实现的,在单个 Python 步骤中执行,因此是线程安全的。
您可能想查看有关Mersenne Twister的文章。简单地说,生成器的状态与“上一个数字”不一样,它要复杂得多。所以你错了«...伪随机数生成器通过对一个值执行一些操作来工作。通常这个值是生成器生成的前一个数字»。
至于SystemRandom.random(),在某种程度上是无关的random.random()。在 Python 中,从不同模块导入的同名函数可能不同,所以这里不能依赖函数名。
| 归档时间: |
|
| 查看次数: |
9793 次 |
| 最近记录: |