gpt4 book ai didi

python - random.random() 在 python 中究竟是如何工作的?

转载 作者:行者123 更新时间:2023-12-03 09:50:01 26 4
gpt4 key购买 nike

我对 random.random() 函数在 python 中的工作方式有点困惑。

docs说它'返回[0.0,1.0)范围内的下一个随机浮点数'。
我知道伪随机数生成器通过对一个值执行一些操作来工作。通常,此值是生成器生成的先前数字。所以我认为这就是 '下一个随机浮点' 这里的意思。 (如果我错了请纠正我)

但是当我看到source code在随机库中,随机函数未在 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

如果我理解正确,这个函数会使用 os.urandom 生成一个随机数。其中,根据 documentation ,从特定于操作系统的随机源返回随机字节。所以这不会给出“下一个”浮点随机数。

两者是如何联系起来的?还是它们是两个不同的东西?

我在这里很困惑。任何形式的帮助将不胜感激。

谢谢!

最佳答案

random python中的模块包含pseudorandom number generators(PRNGs)的两个接口(interface)(类) .您可以将其视为生成随机数的两种方式。

  • 随机使用 Mersenne Twister PRNG .是不是 加密安全
  • 系统随机 使用 /dev/urandom POSIX 上的文件系统或 CryptGenRandom() Windows NT上的功能系统。两者都是Cryptographically secure PRNGs .


  • A note on the module secrets.

    The module secrets does not implement any type of PRNG but provides helper functions(which is awesome because we don't have to write them ourselves) based on SystemRandom and os.urandom(which SystemRandom is based upon). The comments are mine:

    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() 是如何工作的?

    random.random() 在第 749 行的“random.py”模块中定义(对我来说)
    _inst = Random()
    ...
    random = _inst.random

    类(class) random.Random()没有定义 random()方法本身,但继承 _random.Random() (它确实定义了一个名为 random() 的方法),这是一个名为 Random() 的类位于模块 _random .
    C _random的源代码(它是一个内置模块)模块可以找到 here (它实际上被称为 _randommodule.c 。参见下面的解释)

    Naming convention for python modules written in C/C++

    (Historically, if a module is called spam, the C file containing its implementation is called spammodule.c; if the module name is very long, like spammify, the module name can be just 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));
    }
    genrand_int32()是由 Mersenne Twister PRNG 定义的函数返回一个 4 字节数字的实现。

    SystemRandom().random() 是如何工作的?

    (我知道你没有要求 SystemRandom(),但在我写这篇文章的时候我还没有意识到)

    我制作了这张图片作为我的答案的概述(但是,我鼓励您阅读全部内容)

    Overview of SystemRandom's random() method
    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**

    该函数使用模块 os.py 中定义的另一个名为 urandom() 的函数。
    from os import urandom as _urandom
    os.py模块未定义函数 urandom()本身,但从内置模块导入它。 os.py将导入 posix如果您在 POSIX OS 上,则内置模块或 nt如果您在 Windows NT OS 上,则内置模块.这些模块包含 urandom() 的定义。
    if 'posix' in _names:
    name = 'posix'
    linesep = '\n'
    from posix import *

    或者
    elif 'nt' in _names:
    name = 'nt'
    linesep = '\r\n'
    from nt import *

    posix and nt are built-in modules, so they don't have the __file__ attribute.



    潜水 source code :

    POSIX


    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
    }

    • _PyOS_URandom() is defined in the bootstrap_hash.c file which then calls pyurandom()

    int
    _PyOS_URandom(void *buffer, Py_ssize_t size)
    {
    return pyurandom(buffer, size, 1, 1);
    }

    • pyurandom() is defined in the bootstrap_hash.c file which then calls dev_urandom().

    static int
    pyurandom(void *buffer, Py_ssize_t size, int blocking, int raise)
    {
    ...
    return dev_urandom(buffer, size, raise);
    ...
    }

    • dev_urandom is defined in the bootstrap_hash.c file which then uses the /dev/urandom directory to get random bytes.

    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);
    ...
    }

    window

    It may look a bit weird(I thought that as well) but the posixmodule.c file is also used for the NT systems, here is a quote(comment) from the beginning of the file

    This file is also used for Windows NT/MS-Win. In that case the
    module actually calls itself 'nt', not 'posix', and a few functions are either unimplemented or implemented differently. The source
    assumes that for Windows NT, the macro 'MS_WINDOWS' is defined independent of the compiler used. Different compilers define their own feature test macro, e.g. '_MSC_VER'.



    对于 Windows NT,函数调用链与 POSIX 相同,直到 pyurandom() 函数

    • pyurandom() is defined in the bootstrap_hash.c file which then calls 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
    ...
    }

    • win32_urandom() is defined in the bootstrap_hash.c file which then calls CryptGenRandom().

    static int
    win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise)
    {
    ...
    if (!CryptGenRandom(hCryptProv, chunk, buffer))
    {
    ...
    }
    ...
    return 0;
    }

    • CryptGenRandom() is declared in the wincrypt.h file and defined in the Advapi32.lib and Advapi32.dll libraries(These files are provided by Microsoft)

    关于python - random.random() 在 python 中究竟是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41998399/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com