Python随机数生成器的错误:TypeError: unhashable type。

8
在Python3中,random.Random(seed)允许使用bytearray作为种子进行初始化。
class Random(_random.Random):
    ...
    def __init__(self, x=None):
        self.seed(x)
        ...

    def seed(self, a=None, version=2):
        ...
        if version == 2 and isinstance(a, (str, bytes, bytearray)):
            if isinstance(a, str):
                a = a.encode()
            a += _sha512(a).digest()
            a = int.from_bytes(a, 'big')
        ...

当你尝试时

>>> random.Random().__init__(bytearray([1, 2, 3]))

或者

>>> r = random.Random()
>>> r.seed(bytearray([1, 2, 3]))

它应该可以正常工作。

但是当你尝试这样做时,结果是不一致的。

>>> random.Random(bytearray([1, 2, 3]))
TypeError: unhashable type: 'bytearray'

我编译和调试了Python 3.7.0二进制文件,当我尝试使用一个bytearray初始化PRNG时,在Modules/_randommodule.c中会调用random_seed方法并直接在此处引发类型错误。为什么?


第一种选择是创建一个名为r的实例。在最后一个示例中,您不需要这样做。 - Aaron_ab
1
random.Random(x=bytearray([1,2,3]))可以正常运行。(Python 3.6.7,Linux系统,我使用random.Random(bytearray([1,2,3]))也得到了和你一样的错误。)这很奇怪。 - Gilles 'SO- stop being evil'
在Python3中,bytearray 被视为 bytes。因此请尝试使用 bytesrandom.Random(bytes(bytearray([1, 2, 3]))) - I_Al-thamary
这种方式怎么样 random.seed(bytearray([1, 2, 3])) print(random.random()); - I_Al-thamary
2个回答

2
例外并非来自于Random.__init__()方法,而是来自于在__init__()方法之前调用的__new__()方法:
>>> random.Random.__new__(random.Random, bytearray([1,2,3]))
TypeError: unhashable type: 'bytearray'
>>> random.Random.__new__(random.Random, bytes([1,2,3]))
<random.Random at 0x1b0cd78>

1

BlackJack的回答启示了我。我仔细阅读了_random.Random.__new__方法的C源代码

_random.Random.__new__方法(C语言中的random_new)使用相同的参数调用_random.Random.seed方法(C语言中的random_seed)。如果random_seed函数中的args包含一个非整数对象作为种子,则会尝试获取对象的哈希值。因此,当对象是bytearray时,它会引发类型错误。

因此,_random.Random不会特别处理使用bytearray进行种子生成,但它的子类random.Random却可以,这似乎是Python中的不兼容性bug。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接