Mis*_*agi 4 python hash unit-testing python-3.x
我需要获取python使用的随机哈希种子来复制失败的单元测试.
如果PYTHONHASHSEED设置为非零整数,sys.flags.hash_randomization则可靠地提供它:
$ export PYTHONHASHSEED=12345
$ python3 -c 'import sys, os;print(sys.flags.hash_randomization, os.environ.get("PYTHONHASHSEED"))'
12345 12345
Run Code Online (Sandbox Code Playgroud)
但是,如果哈希是随机的,它只是指出该种子使用,而不是其中:
$ export PYTHONHASHSEED=random
$ python3 -c 'import sys, os;print(sys.flags.hash_randomization, os.environ.get("PYTHONHASHSEED"))'
1 random
Run Code Online (Sandbox Code Playgroud)
信息sys.hash_info从不包括取决于种子的数据.使用python3.4之后的哈希函数,尝试从给定的哈希重构种子似乎也是不可行的.
上下文:在微调算法时,我们已经看到了依赖于set/dict迭代次序的heisenbug.复制它们需要测试种子,最糟糕的是所有4294967295,但即使我们平均约100次测试也很长.
我们一直考虑将PYTHONHASHSEED外部设置为随机但已知的值,但我们希望避免使用这个额外的层.
Mar*_*ers 10
不,随机值被分配给union的uc字段,但是这从未暴露给Python代码.那是因为可能值的数量远远大于设置可以产生的值._Py_HashSecretPYTHONHASHSEED
当您未设置PYTHONHASHSEED或设置它时random,Python会生成一个随机的24字节值以用作种子.如果设置PYTHONHASHSEED为整数,那么该数字将通过线性同余生成器传递以生成实际种子(请参阅lcg_urandom()函数).问题是PYTHONHASHSEED仅限于4个字节.种子值比可以PYTHONHASHSEED单独设置的256**20倍.
您可以在访问内部哈希值_Py_HashSecret使用结构ctypes:
from ctypes import (
c_size_t,
c_ubyte,
c_uint64,
pythonapi,
Structure,
Union,
)
class FNV(Structure):
_fields_ = [
('prefix', c_size_t),
('suffix', c_size_t)
]
class SIPHASH(Structure):
_fields_ = [
('k0', c_uint64),
('k1', c_uint64),
]
class DJBX33A(Structure):
_fields_ = [
('padding', c_ubyte * 16),
('suffix', c_size_t),
]
class EXPAT(Structure):
_fields_ = [
('padding', c_ubyte * 16),
('hashsalt', c_size_t),
]
class _Py_HashSecret_t(Union):
_fields_ = [
# ensure 24 bytes
('uc', c_ubyte * 24),
# two Py_hash_t for FNV
('fnv', FNV),
# two uint64 for SipHash24
('siphash', SIPHASH),
# a different (!) Py_hash_t for small string optimization
('djbx33a', DJBX33A),
('expat', EXPAT),
]
hashsecret = _Py_HashSecret_t.in_dll(pythonapi, '_Py_HashSecret')
hashseed = bytes(hashsecret.uc)
Run Code Online (Sandbox Code Playgroud)
但是,您实际上无法对此信息执行任何操作.你不能设置_Py_HashSecret.uc一个新的Python进程,因为这样做会破坏大多数字典密钥集,然后你可以从Python代码(Python内部结构严重依赖字典)这样做,并且你的哈希值等于256*之一*4个可能的LCG值非常小.
你想在PYTHONHASHSEED任何地方设置一个已知值是一个更可行的方法.