Python允许将词典与==
import copy
child = {'name': 'child'}
parent_1 = {'name': 'parent', 'child': child}
parent_2 = copy.deepcopy(parent_1)
print(parent_1 == parent_2)
按照您的预期打印True
。
Python还允许字典循环引用。
child = {'name': 'child'}
parent_1 = {'name': 'parent', 'child': child}
child['parent'] = parent_1 # Create the circular reference
但是,尝试在带有循环引用的字典上使用==
运算符会引发错误。
parent_2 = copy.deepcopy(parent_1)
print(parent_1 == parent_2)
返回
C:\Python34\python.exe -i C:/Users/anon/.PyCharm40/config/scratches/scratch_5
Traceback (most recent call last):
File "C:/Users/anon/.PyCharm40/config/scratches/scratch_5", line 11, in <module>
print(parent_1 == parent_2)
RuntimeError: maximum recursion depth exceeded in comparison
如何检查两个带有循环引用的字典是否相等?
答案 0 :(得分:3)
你需要平等地定义你的意思。通常&#34;相等&#34;对于字典意味着所有的键/值对都是&#34;等于&#34;&#39;。如果字典具有对自身的引用,则此equ等定义可能会导致递归定义,即a == b
iff a == b
。
举个简单的例子:
a = {}; a['item'] = a
b = {}; b['item'] = b
a
和b
是否相等?要了解这一点,您需要先了解a
和b
是否相等......
您可以创建一个特殊的equal
,如下所示:
def equal(a, b, special=[]):
if not isinstance(a, dict) or not isinstance(b, dict):
return a == b
special = special + [a, b]
set_keys = set(a.keys())
if set_keys != set(b.keys()):
return False
for key in set_keys:
if any(a[key] is i for i in special):
continue
elif any(b[key] is i for i in special):
continue
elif not equal(a[key], b[key], special):
return False
return True
答案 1 :(得分:0)
import copy
child = {'name': 'child'}
parent_1 = {'name': 'parent', 'child': child}
child['parent'] = parent_1 # Create the circular reference
parent_2 = copy.copy(parent_1)
print(parent_1 == parent_2)
如果您使用copy.copy
代替copy.deepcopy
,则会运行时没有错误。
浅层和深层复制之间的区别仅与之相关 复合对象(包含其他对象的对象,如列表或 类实例):
•浅拷贝构造一个新的复合对象然后(到 尽可能地将引用插入到找到的对象中 原来。
•深层复制构造一个新的复合对象,然后递归地, 将副本插入原始文件中找到的对象。
https://docs.python.org/2/library/copy.html
这可能是存储问题,使用deepcopy()强制实际递归,而copy()只能检查引用
答案 2 :(得分:0)
你需要编写自己的比较过程,它需要四个参数,两个要比较的东西,两个字典/列表堆栈(每个被比较的东西一个)。
如果要比较的任何东西都包含在相应的堆栈中,如果它们在同一位置的自己的堆栈中则返回true,否则返回false。
否则,如果它们是字典,请确保它们具有相同的键集(否则返回false),并对每个值进行递归,将字典添加到两个堆栈中。
如果它们是列表,请确保它们的长度相同(或返回false)并递归每对成员,将列表添加到两个堆栈中。
要开始工作,请使用要比较的内容和两个空堆栈调用递归过程。您可以将此包装在另一个只带两个参数的过程中。
def my_compare(a, b):
return my_compare_helper(a, b, [], [])
def my_index(thing, stack):
for i in range(len(stack)):
if thing is stack[i]:
return i
return -1
def my_compare_helper(a, b, a_stack, b_stack):
a_loc = my_index(a, a_stack)
b_loc = my_index(b, b_stack)
if a_loc != -1 or b_loc != -1:
return a_loc == b_loc
a_stack = [a] + a_stack
b_stack = [b] + b_stack
if isinstance(a, list):
if not isinstance(b, list) or len(a) != len(b):
return False
for a_thing, b_thing in zip(a, b):
if not my_compare_helper(a_thing, b_thing, a_stack, b_stack):
return False
return True
if isinstance(a, dict):
if not isinstance(b, dict):
return False
a_keys = sorted(a.keys())
b_keys = sorted(b.keys())
if a_keys != b_keys: # Keys can't be recursive.
return False
for key in a_keys:
if not my_compare_helper(a[key], b[key], a_stack, b_stack):
return False
return True
return a == b
样本用法:
>>> a = [1, 2, {}]
>>> a[1] = a
>>> a[2]['x'] = a
>>> b = [1, 2, {}]
>>> b[1] = b
>>> b[2]['x'] = b
>>> my_compare(a, b)
True
>>>
答案 3 :(得分:0)
当我做其他事情时,我发现了pickle模块处理递归字典等。考虑到这一点,这可能对你有用:
import copy
import cPickle
a = {}
a['self'] = a
a['list'] = [a, a, 0]
b = copy.deepcopy(a)
print(cPickle.dumps(a) == cPickle.dumps(b))
# True
b['self'] = copy.deepcopy(b)
print(cPickle.dumps(a) == cPickle.dumps(b))
# False