python – 比较dict子类的实例
发布时间:2020-12-20 12:27:31 所属栏目:Python 来源:网络整理
导读:我有子类dict添加一个额外的方法(所以没有覆盖). 现在,我尝试比较其中两个子类,我得到一些奇怪的东西: d1.items() == d2.items()True d1.values() == d2.values()True d1.keys() == d2.keys()True d1 == d2False 编辑 那真是太奇怪了……我根本不明白!谁有
我有子类dict添加一个额外的方法(所以没有覆盖).
现在,我尝试比较其中两个子类,我得到一些奇怪的东西: >>> d1.items() == d2.items() True >>> d1.values() == d2.values() True >>> d1.keys() == d2.keys() True >>> d1 == d2 False 编辑 那真是太奇怪了……我根本不明白!谁有洞察dict.eq是如何实现的? 以下是所有代码: # ------ 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,AllSubSetsOf): return self.klass == other.klass else: return False def __lt__(self,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没有任何关系.事实上,使用常规字典可以看到这种行为.问题是如何定义您正在使用的密钥.一个简单的类,如:
>>> 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 缺少的是你忘了定义__hash__.每次更改类的相等语义时,都应确保__hash__方法与它一致:当两个对象相等时,它们必须具有相等的哈希值. dict行为很大程度上取决于键的哈希值. 当你从object继承时,你自动获得__eq__和__hash__,前者比较对象标识,后者返回对象的地址(所以他们同意),但是当你改变__eq__时,你仍然看到旧的__hash__,不再同意和dict迷失了. 只需提供一个__hash__方法,以稳定的方式组合其属性的哈希值. >>> class Bar(object): ... def __init__(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 >>> 以这种方式使用__hash__时,确保在创建对象后属性不会(或更好,不能)更改也是一个好主意.如果哈希值在dict中收集时发生变化,则密钥将“丢失”,并且可能发生各种奇怪的事情(甚至比您最初询问的问题更奇怪) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |