加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

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中收集时发生变化,则密钥将“丢失”,并且可能发生各种奇怪的事情(甚至比您最初询问的问题更奇怪)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读