python2和python3中dict的__repr__()

Posted

技术标签:

【中文标题】python2和python3中dict的__repr__()【英文标题】:dict's __repr__() in python2 and python3 【发布时间】:2013-11-02 11:25:37 【问题描述】:

我在一个代码库(2.6、2.7 和 3.3+)中仅将 python 库从 python 2 移植到 python 2 和 3。剩下的主要问题是很多测试都使用这样的东西:

def test(self):
 example = u'foo': u'bar'
 self.assertEqual(str(example), "u'foo': u'bar'")

在 python 2 中有效,但在 python3 中引发异常:

 AssertionError: "'foo': 'bar'" != "u'foo': u'bar'"

除了“测试不同”之外,还有处理这些问题的标准方法吗?重载__repr__?

【问题讨论】:

为什么要进行这些测试?他们试图验证什么?这闻起来很强烈XY problem。 澄清一下:在实际代码中,example是dict的子类,是另一个函数的返回值。这个子类有它自己的__repr__,包装了dict的__repr__,但是'u's还在里面 这并没有说明任何事情。你到底想在这里测试什么?问题是子类的__eq__ 不能与基本dict 对象一起工作,所以您试图通过比较它们的repr 来解决它?还是……? @ChristianGeier:您正在与固定字符串进行比较;如果您测试自定义__repr__,则生成带有或不带有u前缀的固定字符串。 @abarnert __eq__ 确实有效,我不知道为什么原作者通过__repr__ 进行测试。我想我会使用它并完成它。 【参考方案1】:

摆脱那些测试;它们几乎没用:

这将测试dict.__repr__ 的 Python 实现是否正常工作。 Python 本身已经对此进行了测试;而是专注于项目代码库。如果 Python 无法正确呈现字典表示,则修复该问题不是您项目的工作。

Python 字典没有固定的顺序;测试它们的表示是否与给定的字符串匹配是不稳定的。

此外,Python 3.3 引入了哈希随机化,这意味着给定字典的顺序将在每次调用中发生变化。见PYTHONHASHSEED

如果您正在测试项目 API 调用的结果,请改用 self.assertEqual() 测试字典是否相等;如果两个字典不匹配,它将使用assertDictEqual() 为您提供有意义的错误消息。

由于 Python 3.3 将 u'foo' 解释为类型 str 的文字,因此将输出与 u'foo': u'bar 进行比较将适用于 Python 2.6、2.7 和 3.3 及更高版本。

【讨论】:

另外,在 python3 中,字符串默认变成了 unicode。这意味着标准字符串不再有 u 前缀。 检查self.assertEqual(example, ast.literal_eval(u'foo': u'bar')) 不太可能,并且服务于类似目的......但我仍然无法想象那个目的可能是什么,所以很难说它是否相似够了 @MartijnPieters,公平地说,在 this 示例中排序无关紧要:len(example) == 1 assertDictEqual 在 2.6 中不存在。而在 2.7 和 3.3 中,虽然它确实存在,但“此方法将默认用于比较对 assertEqual() 的调用中的字典”,因此不会增加太多。 @TimPeters:当然;但 OP 没有测试长度;他正在测试 Python dict.__repr__() 是否仍在工作..【参考方案2】:

我怀疑这不是您的真实代码,而您的真实代码正在做一些不那么愚蠢的事情:尝试验证字典是否与某些预期结果匹配。

这样做的方法是直接比较字典,而不是比较它们的字符串表示:

self.assertEqual(example, u'foo': u'bar')

这适用于 2.x 和 3.x(因为您需要 3.3+,这意味着 u 前缀是合法的,如果不需要的话)。

【讨论】:

以上是关于python2和python3中dict的__repr__()的主要内容,如果未能解决你的问题,请参考以下文章

unicode_literals 和 type()

python2.X与Python3.X区别

Python 比较两个字典大小

python3 与dict相关的魔法方法。使用于二叉搜索树的类中

Python2与Python3兼容

python3学习笔记_dict-set