Python:在哪里是random.random()seeded? [英] Python: where is random.random() seeded?

查看:209
本文介绍了Python:在哪里是random.random()seeded?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

说我有一些python代码:

  import random 
r = random.random()

一般来说,r种子的值在哪里?

如果我的操作系统没有随机,那么它在哪里种子?

为什么不推荐用于加密?

解决方案

按照 da code p>

要查看系统中随机模块的位置,您只需在终端中执行:

 >>> import random 
>>>> random .__ file__
'/usr/lib/python2.7/random.pyc'

这为你提供了 .pyc (编译的)文件的路径,它通常与原来的 .py 其中可以找到可读代码。



让我们看看 /usr/lib/python2.7/random.py 中发生了什么:



你会看到它创建了一个 Random 类的实例,然后(在文件的底部) 该实例的方法到模块函数。整洁的技巧。当在任何地方导入 random 模块时,创建该 Random 类的新实例,然后初始化其值,方法重新分配为模块的函数(使其在每次导入的基础上非常随机)

  _inst = Random ()
seed = _inst.seed
random = _inst.random
uniform = _inst.uniform
triangular = _inst.triangular
randint = _inst.randint

Random code> __ init __ 方法正在播种:

  class Random(_random.Random): 
...
def __init __(self,x = None):
self.seed(x)
...
_inst = Random b seed = _inst.seed

所以...如果 x (没有指定种子)?好吧,让我们检查 self.seed 方法:

  def seed self,a = None):
从hashable对象初始化内部状态

当前时间或操作中没有或没有参数种子
系统特定随机源if

如果a不是None或int或long,则使用hash(a)。


如果a是None:
try:
a = long(_hexlify(_urandom(16)),16)
除了NotImplementedError:
import time
a = long(time.time #use fractional seconds

super(Random,self).seed(a)
self.gauss_next = None

注释已经告诉了发生了什么...这个方法尝试使用操作系统提供的默认随机生成器,如果没有,那么它将使用当前时间作为种子值。



但是,等等...什么是 _urandom(16) / p>

好吧,答案在于 random.py 文件的开头:



来自os import urandom as _urandom
来自binascii import hexlify as _hexlify

Tadaaa ...种子是一个16字节的数字,来自 os.urandom



假设我们在一个文明的操作系统,如Linux真实随机数生成器)。 random 模块使用的种子与执行以下操作相同:

  >>>> long(bins.ciand.hexlify(os.urandom(16)),16)
46313715670266209791161509840588935391L

为什么指定种子值的原因被认为不是那么大是 random 函数不是真正的随机...他们只是一个非常奇怪的数字序列。但是,对于相同的种子,该序列将是相同的。您可以自己尝试:

 >>> import random 
>>>> random.seed(1)
>>>> random.randint(0,100)
13
>>>> random.randint(0,100)
85
>>>> random.randint(0,100)
77

无论何时或如何,其中您运行该代码(只要用于生成随机数的算法保持不变),如果您的种子 1 ,您将始终获得整数 13 85 77 的目的(参见关于伪随机数生成的)。另一方面, a href =http://stackoverflow.com/a/20636902/289011>用例,但这实际上是一个理想的功能。



这就是为什么被认为是更好依赖于操作系统的随机数发生器。这些通常是基于硬件中断计算的,这些中断非常非常随机(包括中断用于硬盘读取,由用户键入的键击,移动鼠标...)在Linux中,该操作系统生成器是 / dev / random 。或者,作为一个tad picky, / dev / urandom (这是Python的 os.urandom 实际使用内部)是(如前所述) / dev / random 使用硬件中断来生成随机序列。如果没有中断, / dev / random 可能会用尽,你可能需要等待一点,直到你可以得到下一个随机数。 / dev / urandom 在内部使用 / dev / random ,但它确保它始终具有随机数。



如果你使用linux,只需在终端上执行 cat / dev / random

  borrajax @ borrajax: / tmp $ cat / dev / random 
_ + _ ?zta K q ߤk / qSlV { Gzk` #p $ *C F B9 o〜, QH ɭ f ޺ ̬po 2o

Say I have some python code:

import random
r=random.random()

Where is the value of r seeded from in general?
And what if my OS has no random, then where is it seeded?
Why isn't this recommended for cryptography? Is there some way to know what the random number is?

解决方案

Follow da code.

To see where the random module "lives" in your system, you can just do in a terminal:

>>> import random
>>> random.__file__
'/usr/lib/python2.7/random.pyc'

That gives you the path to the .pyc ("compiled") file, which is usually located side by side to the original .py where readable code can be found.

Let's see what's going on in /usr/lib/python2.7/random.py:

You'll see that it creates an instance of the Random class and then (at the bottom of the file) "promotes" that instance's methods to module functions. Neat trick. When the random module is imported anywhere, a new instance of that Random class is created, its values are then initialized and the methods are re-assigned as functions of the module (making it quite random on a per-import basis)

_inst = Random()
seed = _inst.seed
random = _inst.random
uniform = _inst.uniform
triangular = _inst.triangular
randint = _inst.randint

The only thing that this Random class does in its __init__ method is seeding it:

class Random(_random.Random):
    ...
    def __init__(self, x=None):
        self.seed(x)    
...
_inst = Random()
seed = _inst.seed

So... what happens if x is None (no seed has been specified)? Well, let's check that self.seed method:

def seed(self, a=None):
    """Initialize internal state from hashable object.

    None or no argument seeds from current time or from an operating
    system specific randomness source if available.

    If a is not None or an int or long, hash(a) is used instead.
    """

    if a is None:
        try:
            a = long(_hexlify(_urandom(16)), 16)
        except NotImplementedError:
            import time
            a = long(time.time() * 256) # use fractional seconds

    super(Random, self).seed(a)
    self.gauss_next = None

The comments already tell what's going on... This method tries to use the default random generator provided by the OS, and if there's none, then it'll use the current time as the seed value.

But, wait... What the heck is that _urandom(16) thingy then?

Well, the answer lies at the beginning of this random.py file:

from os import urandom as _urandom
from binascii import hexlify as _hexlify

Tadaaa... The seed is a 16 bytes number that came from os.urandom

Let's say we're in a civilized OS, such as Linux (with a real random number generator). The seed used by the random module is the same as doing:

>>> long(binascii.hexlify(os.urandom(16)), 16)
46313715670266209791161509840588935391L

The reason of why specifying a seed value is considered not so great is that the random functions are not really "random"... They're just a very weird sequence of numbers. But that sequence will be the same given the same seed. You can try this yourself:

>>> import random
>>> random.seed(1)
>>> random.randint(0,100)
13
>>> random.randint(0,100)
85
>>> random.randint(0,100)
77

No matter when or how or even where you run that code (as long as the algorithm used to generate the random numbers remains the same), if your seed is 1, you will always get the integers 13, 85, 77... which kind of defeats the purpose (see this about Pseudorandom number generation) On the other hand, there are use cases where this can actually be a desirable feature, though.

That's why is considered "better" relying on the operative system random number generator. Those are usually calculated based on hardware interruptions, which are very, very random (it includes interruptions for hard drive reading, keystrokes typed by the human user, moving a mouse around...) In Linux, that O.S. generator is /dev/random. Or, being a tad picky, /dev/urandom (that's what Python's os.urandom actually uses internally) The difference is that (as mentioned before) /dev/random uses hardware interruptions to generate the random sequence. If there are no interruptions, /dev/random could be exhausted and you might have to wait a little bit until you can get the next random number. /dev/urandom uses /dev/random internally, but it guarantees that it will always have random numbers ready for you.

If you're using linux, just do cat /dev/random on a terminal (and prepare to hit Ctrl+C because it will start output really, really random stuff)

borrajax@borrajax:/tmp$ cat /dev/random
_+�_�?zta����K�����q�ߤk��/���qSlV��{�Gzk`���#p$�*C�F"�B9��o~,�QH���ɭ�f�޺�̬po�2o
                        

这篇关于Python:在哪里是random.random()seeded?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆