2016-04-28 23 views
1

每个人。我最近从Python 2切换到3.5.1,并且有一个断言函数,我不能重写。如何断言没有订单的字典的两个列表?

def assertEqualUnordered(self, data1, data2): 
    """ 
    compare that data are similar 
    i.e.: 
    [d1, d2] == [d2, d1] 
    or 
    {'a': [d1, d2]} == {'a': [d2, d1]} 
    or 
    [{'a': [d1, d2]}, {'b': [d3, d4]}] == [{'b': [d4, d3]}, {'a': [d2, d1]}] 
    """ 
    if isinstance(data1, list) or isinstance(data1, tuple): 
     self.assertEqual(len(data1), len(data2)) 
     for d1, d2 in zip(sorted(data1), sorted(data2)): 
      self.assertEqualUnordered(d1, d2) 
    elif isinstance(data1, dict): 
     data1_keys = sorted(data1.keys()) 
     data2_keys = sorted(data2.keys()) 
     self.assertListEqual(data1_keys, data2_keys) 
     for key in data1_keys: 
      self.assertEqualUnordered(data1[key], data2[key]) 
    else: 
     self.assertEqual(data1, data2) 

一般这种代码工作正常,但如果D1和D2类型的字典,比我有:

TypeError: unorderable types: dict() < dict()

我怎样才能把它改写在py3k工作?

编辑1: 简化代码示例:

def assertEqualUnordered(data1, data2): 
    assert len(data1) == len(data2) 
    for d1, d2 in zip(sorted(data1), sorted(data2)): 
     assert d1 == d2 

data1 = [{'a': 'a'}, {'b': 'b'}] 
data2 = [{'b': 'b'}, {'a': 'a'}] 
assertEqualUnordered(data1, data2) 
+0

您是否可以简化这一步,以便更仔细地了解您遇到的故障?我认为这与key()返回视图而不是列表有关。 https://docs.python.org/3.0/whatsnew/3.0.html 此外,你可以包括完整的堆栈跟踪? – jgritty

+0

显示引发异常的代码:此代码不在任何地方使用'<'。 –

+0

@jgritty简化代码示例 – vanadium23

回答

3

我不知道这是否是做的最简单的方法,但你可以通过复活的cmp功能的Python使这类工作3被删除。沿着这些路线的东西:

def cmp(lhs, rhs): 
    try: 
     if lhs == rhs: 
      return 0 
     elif lhs < rhs: 
      return -1 
     else: 
      return 1 
    except TypeError: 
     if isinstance(lhs, dict) and isinstance(rhs, dict): 
      return dict_cmp(lhs, rhs) 
     raise 

对于dict_cmp执行看到Is there a description of how __cmp__ works for dict objects in Python 2?

一旦你有你cmp功能,你可以做sorted(data1, key = functools.cmp_to_key(cmp))

这仍然不完整,因为我还没有试图涵盖混合类型的比较,例如,如果您通过[{'a' : 'b'}, ['a']]作为其中一个对象,会出现这种比较。但希望我已经提供了一个方向。

另一种方法是回退到O(n^2)算法,该算法实际上符合Python3的意见,即字典没有顺序。不要对列表进行排序,然后比较它们是否相等,然后依次取左侧的每个项目并搜索右侧的项目(与删除项目相同),以确保双方的计数相同,因为您不想错误地声称[x, x, y]等于​​)。

顺便说一句,没有真正必要的答案,但我注意到,你现在的代码会说['a', 'b']是无序的{'a' : 'foo', 'b' : 'bar'},但只有当列表在左边,字典在右边。如果您以其他方式通过他们,您会在代码尝试在列表中调用keys()时发生异常。这可能需要解决,具体取决于您计划通过的内容;-)

相关问题