Mat*_*zol 5 python python-unittest
在Python 2.7版文档指出,assertItemsEqual"是相当于assertEqual(sorted(expected), sorted(actual))".在下面的示例中,除test4之外的所有测试都通过.为什么assertItemsEqual在这种情况下会失败?
根据最不惊讶的原则,给定两个迭代,我希望成功assertEqual意味着成功assertItemsEqual.
import unittest
class foo(object):
def __init__(self, a):
self.a = a
def __eq__(self, other):
return self.a == other.a
class test(unittest.TestCase):
def setUp(self):
self.list1 = [foo(1), foo(2)]
self.list2 = [foo(1), foo(2)]
def test1(self):
self.assertTrue(self.list1 == self.list2)
def test2(self):
self.assertEqual(self.list1, self.list2)
def test3(self):
self.assertEqual(sorted(self.list1), sorted(self.list2))
def test4(self):
self.assertItemsEqual(self.list1, self.list2)
if __name__=='__main__':
unittest.main()
Run Code Online (Sandbox Code Playgroud)
这是我机器上的输出:
FAIL: test4 (__main__.test)
----------------------------------------------------------------------
Traceback (most recent call last):
File "assert_test.py", line 25, in test4
self.assertItemsEqual(self.list1, self.list2)
AssertionError: Element counts were not equal:
First has 1, Second has 0: <__main__.foo object at 0x7f67b3ce2590>
First has 1, Second has 0: <__main__.foo object at 0x7f67b3ce25d0>
First has 0, Second has 1: <__main__.foo object at 0x7f67b3ce2610>
First has 0, Second has 1: <__main__.foo object at 0x7f67b3ce2650>
----------------------------------------------------------------------
Ran 4 tests in 0.001s
FAILED (failures=1)
Run Code Online (Sandbox Code Playgroud)
有趣的是,文档规范与实现分离,它从不进行任何排序。这是源代码。正如您所看到的,它首先尝试使用 进行散列计数collections.Counter。如果此操作因类型错误而失败(因为任一列表包含不可散列的项目),则会继续使用第二个算法,在其中使用 python==和 O(n^2) 循环进行比较。
因此,如果您的foo类不可散列,则第二个算法将发出匹配信号。但它是完全可散列的。来自文档:
默认情况下,作为用户定义类实例的对象是可哈希的;它们的比较都不相等(除了它们自己),它们的哈希值来自它们的 id()。
我通过致电验证了这一点collections.Counter([foo(1)])。没有类型错误异常。
所以这就是你的代码脱轨的地方。从文档中__hash__:
如果它定义了cmp () 或eq () 但没有定义hash (),则其实例将无法在散列集合中使用。
不幸的是,“不可用”显然并不等于“不可散列”。
它接着说:
从父类继承hash () 方法但更改cmp () 或eq ()含义的类,使得返回的哈希值不再合适(例如,通过切换到基于值的相等概念而不是默认值)基于身份的平等)可以通过在类定义中 设置hash = None 来显式地将自己标记为不可散列。
如果我们重新定义:
class foo(object):
__hash__ = None
def __init__(self, a):
self.a = a
def __eq__(self, other):
return isinstance(other, foo) and self.a == other.a
Run Code Online (Sandbox Code Playgroud)
所有测试均通过!
因此,这些文件似乎并不完全错误,但也不够清晰。他们应该提到计数是通过散列完成的,只有在失败时才尝试简单的相等匹配。仅当对象具有完整的散列语义或完全不可散列时,这才是有效的方法。你的处于中间立场。(我相信 Python 3 对于禁止或至少警告此类类型更加严格。)
| 归档时间: |
|
| 查看次数: |
895 次 |
| 最近记录: |