Python 比较dict子类的实例
我已经将dict子类化以添加一个额外的方法(因此没有重写) 现在,我试着比较这两个子类,我得到了一些奇怪的东西:Python 比较dict子类的实例,python,Python,我已经将dict子类化以添加一个额外的方法(因此没有重写) 现在,我试着比较这两个子类,我得到了一些奇怪的东西: >>> d1.items() == d2.items() True >>> d1.values() == d2.values() True >>> d1.keys() == d2.keys() True >>> d1 == d2 False 编辑 那太奇怪了。。。我一点也不明白!有谁知道情商是如何实现的吗 以下
>>> d1.items() == d2.items()
True
>>> d1.values() == d2.values()
True
>>> d1.keys() == d2.keys()
True
>>> d1 == d2
False
编辑
那太奇怪了。。。我一点也不明白!有谁知道情商是如何实现的吗
以下是所有代码:
# ------ Bellow is my dict subclass (with no overriding) :
class ClassSetDict(dict):
def subsetget(self, klass, default=None):
class_sets = set(filter(lambda cs: klass <= cs, self))
# Eliminate supersets
for cs1 in class_sets.copy():
for cs2 in class_sets.copy():
if cs1 <= cs2 and not cs1 is cs2:
class_sets.discard(cs2)
try:
best_match = list(class_sets)[0]
except IndexError:
return default
return self[best_match]
# ------ Then an implementation of class sets
class ClassSet(object):
# Set of classes, allowing to easily calculate inclusions
# with comparison operators : `a < B` <=> "A strictly included in B"
def __init__(self, klass):
self.klass = klass
def __ne__(self, other):
return not self == other
def __gt__(self, other):
other = self._default_to_singleton(other)
return not self == other and other < self
def __le__(self, other):
return self < other or self == other
def __ge__(self, other):
return self > other or self == other
def _default_to_singleton(self, klass):
if not isinstance(klass, ClassSet):
return Singleton(klass)
else:
return klass
class Singleton(ClassSet):
def __eq__(self, other):
other = self._default_to_singleton(other)
return self.klass == other.klass
def __lt__(self, other):
if isinstance(other, AllSubSetsOf):
return issubclass(self.klass, other.klass)
else:
return False
class AllSubSetsOf(ClassSet):
def __eq__(self, other):
if isinstance(other, AllSubSetsOf):
return self.klass == other.klass
else:
return False
def __lt__(self, other):
if isinstance(other, AllSubSetsOf):
return issubclass(self.klass, other.klass) and not other == self
else:
return False
# ------ and finally the 2 dicts that don't want to be equal !!!
d1 = ClassSetDict({AllSubSetsOf(object): (int,)})
d2 = ClassSetDict({AllSubSetsOf(object): (int,)})
#----下面是我的dict子类(没有重写):
类别ClassSetDict(dict):
def子集合(自身、klass、默认值=无):
class_sets=set(filter(lambda cs:klass这很可能取决于一些实现细节,实际上一个基本的子类化并没有显示这个问题:
>>> class D(dict):
... def my_method(self):
... pass
...
>>> d1 = D(alpha=123)
>>> d1
{'alpha': 123}
>>> d2 = D(alpha=123)
>>> d1.items() == d2.items()
True
>>> d1.values() == d2.values()
True
>>> d1.keys() == d2.keys()
True
>>> d1 == d2
True
“AllSubSetsOf”的实例用作dict键——它们应该有一个散列方法。
尝试添加一个
def __hash__(self):
return hash(self.klass)
无论是类集还是所有子集的方法,我都讨厌人们说“dicts包含时髦的东西,所以它对显示没有多大帮助”,因为在这里,时髦的东西的本质才是最重要的
首先要注意的是,如果得到的结果正好相反,这一点也不奇怪:即如果d1.items()、d1.values()、d1.keys()
不等于d2.items()、d2.values()、d2.keys()
你可以很高兴地拥有d1==d2
。这是因为字典不会通过比较项目或键来进行比较,它们使用不同的技术,我认为这是你问题的根源
有效地比较两个字典首先检查它们的长度是否相同,然后检查第一个字典中的所有键,以找到与第二个字典中的键/值不匹配的最小键。因此,我们实际上要查找的是d1.keys()==d2.keys()
但对于某些k,要么k不在d1中,要么k不在d2中,要么d1[k]!=d2[k]
我认为线索可能在你用作字典键的对象中。如果它们是可变的,你可以将一个对象存储在字典中,但随后对其进行变异,然后通过正常方式无法访问它。keys()
方法仍然可以找到它,在这种情况下,你可以得到你看到的东西
现在,您已经用AllSubSetsOf
类更新了问题:问题出在缺少的\uuuu hash\uuuu()
方法上。两个不同的实例可以比较相等:AllSubSetsOf(object)==AllSubSetsOf(object)
,但哈希值只是对地址进行哈希运算,因此它们会不同
>>> class AllSubSetsOf(object):
def __init__(self, klass):
self.klass = klass
def __eq__(self, other):
if isinstance(other, AllSubSetsOf):
return self.klass == other.klass
else:
return False
def __lt__(self, other):
if isinstance(other, AllSubSetsOf):
return issubclass(self.klass, other.klass) and not other == self
else:
return False
>>> a = AllSubSetsOf(object)
>>> b = AllSubSetsOf(object)
>>> a==b
True
>>> hash(a), hash(b)
(2400161, 2401895)
>>>
您遇到的问题与子类化dict
无关。事实上,使用常规dict可以看到这种行为。问题在于如何定义您使用的键。一个简单的类,如:
>>> class Foo(object):
... def __init__(self, value):
... self.value = value
...
... def __eq__(self, other):
... return self.value == other.value
...
足以证明问题:
>>> f1 = Foo(5)
>>> f2 = Foo(5)
>>> f1 == f2
True
>>> d1 = {f1: 6}
>>> d2 = {f2: 6}
>>> d1.items() == d2.items()
True
>>> d1 == d2
False
缺少的是您忘记了定义\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
。每次更改类的相等语义时,您都应该确保\uuuuuuuuuuuuuuu
当您从对象
继承时,您会自动获得\uuuuueq\uuuuu
和\uuuuuuuhash\uuuuuuu
,前者比较对象标识,后者返回对象的地址(因此他们同意),但当您更改\uuuuu eq\uuuuu
时,仍会看到旧的\uuuuu hash\uuuuuu
,它不再一致,并且dict
丢失
只需提供一个\uuuuuuuuuuuuuuuu散列
方法,该方法以稳定的方式组合其属性的散列值
>>> class Bar(object):
... def __init__(self, value):
... self.value = value
...
... def __eq__(self, other):
... return self.value == other.value
...
... def __hash__(self):
... return hash((Bar, self.value))
...
>>> b1 = Bar(5)
>>> b2 = Bar(5)
>>> {b1: 6} == {b2: 6}
True
>>>
当以这种方式使用\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu看看你是如何对dict
进行子分类的吧!:)向我们展示代码!:)d1和d2是同一类型的吗?是的,同一类型…@mac:Yeaaah:)我知道。。。但它是如此的怪异以至于我想如果有人知道这是一个普遍的问题会更好!但是好吧。。。我会给你看…Phimueme,不管怎样,这应该行得通。max是对的,我们需要看看代码。你必须做得更多。你的ClassSetDict不能显示那种行为。做得好。。。我当时正在研究一种完全不同的思路(场景的可排序性),这时我幸运地看到了你的帖子,省去了自己的羞耻感!)+太好了!!!它起作用了!还有一个问题。。。你认为散列(self.\uuu class.\uuu.\uuu name.\uuuu)+散列(self.klass)
是类集的好散列吗?我特别想知道散列(self.klass)
对类进行散列。我记得根据导入类的方式,我有一些奇怪的行为:-使用self.\uuu class\uuuu
可能是一个糟糕的主意,如果您可能使用子类;散列值将会改变(因为类型已经改变),但相等性不会改变,因此您回到了原点。事实上,拼写课堂是避免问题的好方法。另一种解决方案是将类完全从哈希计算中删除,但当属性(value
在我的示例中)本身在集合中时,这可能会导致不希望的冲突。(另外,在散列计算中不应使用+
;将散列值与^
组合以保留散列分布并避免算术溢出;\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu((Bar,self.value))
将以比简单的异或稍微复杂的适当方式组合Bar
和self.value
的散列。如果@sebpiq开始在散列中包含两个布尔标志,这将很重要。