【问题标题】:Repeatably hashing an arbitrary Python tuple可重复地散列任意 Python 元组
【发布时间】:2018-07-08 20:16:44
【问题描述】:

我正在编写一个专门的单元测试工具,它需要保存测试结果以供将来比较。因此,我需要能够始终如一地将传递给每个测试的参数映射到测试结果,该测试结果是使用每个版本的这些参数运行测试函数。我希望有一种方法可以对元组进行哈希处理,并使用该哈希来命名我存储测试结果的文件。

我的第一个冲动只是在参数元组上调用 hash(),但当然这不会起作用,因为 hash 现在在解释器实例之间是随机的。

我很难想出一种适用于元组中可能存在的任意元素的方法(我想将其限制为整数、浮点数、字符串和列表的混合)这三个元组会好好地)。有什么想法吗?

我曾考虑过使用元组的repr 或对其进行酸洗,但不能保证 repr 为相同的输入产生逐字节相同的输出,而且我认为酸洗也不是(是吗?)

我已经看过this,但答案都是基于不再成立的相同假设,无论如何也不会真正转化为这个问题,很多讨论都是关于使哈希不取决于订单项目的出现,我确实希望哈希取决于订单。

【问题讨论】:

  • 我会将参数的元组腌制到同一个文件中,该文件的名称是参数的散列元组。这样,您不必担心随机化,因为原始元组在文件中。
  • @DYZ 对,我也在这样做,但我需要重复地对元组进行哈希处理,以便能够首先找到文件。
  • @ShadowRanger 我想这...会起作用,但它非常不雅,而且从技术上讲,有人可以使用特制的合并请求对我的 CI 服务器进行 DOS 操作。
  • @Schilcote:所以如果这是一个面向公众的服务器,那是个坏主意;这个问题听起来好像这只是用于可重复的(假设是本地的)单元测试。

标签: python hash


【解决方案1】:

不确定我是否完全理解您的问题,但会试一试。

在进行哈希之前,只需将结果序列化为 JSON 字符串,然后对 JSON 字符串进行哈希计算。

params = (1, 3, 2)
hashlib.sha224(json.dumps(params)).hexdigest()
# '5f0f7a621e6f420002d54ee28b0c169b8112ef72d8a6b60e6a25171c'

如果您的参数是字典,请使用 sort_keys=True 确保您的键已排序。

params = {'b': 123, 'c': 345}
hashlib.sha224(json.dumps(params, sort_keys=True)).hexdigest()
# '2e75966ce3f1185cbfb4eccc49d5552c08cfb7502a8765fe1dce9303'

【讨论】:

  • JSON结果是否保证每次都一样?
  • @Schilcote 对于 liststuples(以及任何稳定的原语)应该是。
  • 如果你正在序列化一个元组/列表,那么是的。
  • 对于字典,您可以将sort_keys 设置为True
  • @DYZ:注意:sort_keys 仅适用于 Python 3,前提是键是同构类型(或者为所有异构类型对定义了比较,例如 int 和 @ 的混合) 987654327@ 很好,但 intstr 不是)。在 Python 2 上,回退比较允许它(通常)工作(尽管不一定可重复,因为相同类型的回退比较基于内存地址,这是不可重复的),但在 Python 3 上,您只会得到一个TypeError.
【解决方案2】:

简单测试的一种方法是通过在启动脚本的环境中设置PYTHONHASHSEED=0 来设置disable the hash randomization entirely,例如在bash 中,执行以下操作:

export PYTHONHASHSEED=0

【讨论】:

  • 注意:这仅适用于本地测试的情况;在面向公众的 Web 服务上执行此操作会使您面临拒绝服务攻击(哈希随机化旨在保护您免受攻击)。
  • 禁用随机化不会解决hash(-1) == hash(-2) 的问题,因为所有整数都对自己进行哈希处理,除了-1,它哈希到-2(至少最近在Python 3.8.2)
  • @mkoistinen:确定吗?但这是一般散列的问题,与这个答案无关。哈希随机化旨在消除制造碰撞哈希的能力;禁用它可以让您像发现碰撞ints 一样容易地找到碰撞字符串。 hashint 可能会发生冲突,无论您是否禁用它。
  • 我的回复不是对您有用的帖子的批评,也不是我对它投反对票,而是我的评论是对尝试使用 hash() 的其他人的警告,类似于原始问题。跨度>
猜你喜欢
  • 2014-04-20
  • 2016-09-05
  • 1970-01-01
  • 2012-06-02
  • 2012-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多