2016-04-28 46 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()時發生異常。這可能需要解決,具體取決於您計劃通過的內容;-)