重写__eq__函数——对象list中使用in index()——获得list中不同属性对象个数

对于用list的元素为对象时,在使用in list和index()函数需要注意。

只实现__init__函数

class user:
    def __init__(self,uid):
        self.uid = uid
list1=[user(0),user(1),user(2)]

print( user(1) in list1 )
print( list1.index(user(1)) )

运行结果:
这里写图片描述
当判断一个对象是否在对象list中时,实际上,是在调用对象的__eq__函数,而默认的__eq__函数是在比较两个对象的存储地址,所以index函数会报错,报错信息为<__main__.user object at 0x0000000002E72518> is not in list

并且重写__eq__函数

class user:
    def __init__(self,uid):
        self.uid = uid
    def __eq__(self,other):
        if(type(self)==type(other)):
            return self.uid==other.uid
        else:
            return False
list1=[user(0),user(1),user(2)]

print( user(1) in list1 )
print( list1.index(user(1)) )

运行结果:这里写图片描述
发现,实现__eq__函数后,就覆盖掉了默认的__eq__函数了。且可以按照我们想要方式比较,即比较对象的成员的值,而不是比较对象的地址

优雅地重写__eq__函数

继续在百度搜了搜,没什么想要的,就去谷歌了,发现stackoverflow有一个类似问题,高票答案写得很好,网址在此Elegant ways to support equivalence (“equality”) in Python classes

class Foo:
    def __init__(self, item):
        self.item = item

    def __eq__(self, other):
        if isinstance(other, self.__class__):
            return self.__dict__ == other.__dict__
        else:
            return False
print(Foo(0) == Foo(0))#结果为True

重写__hash__函数(为了获得list拥有不同属性对象的个数)

class Foo:
    def __init__(self, item):
        self.item = item

    def __eq__(self, other):
        if isinstance(other, self.__class__):
            return self.__dict__ == other.__dict__
        else:
            return False
    def __hash__(self):
        print('id',id(self))
        return hash(id(self))
f1 = Foo(1)
f2 = Foo(1)
f3 = Foo(1)
print(set([f1, f2, f3]))
print(len(set([f1, f2, f3])))

运行结果:
这里写图片描述
可见,每个对象的id都不一样,而且每次创建集合时,都会调用一遍每个元素的hash函数。但这样写,还获得不到list拥有不同属性对象的个数,下面是正确的写法。

class Foo:
    def __init__(self, item):
        self.item = item

    def __eq__(self, other):
        if isinstance(other, self.__class__):
            return self.__dict__ == other.__dict__
        else:
            return False
    def __hash__(self):
        """Overrides the default implementation"""
        return hash(tuple(sorted(self.__dict__.items())))
f1 = Foo(1)
f2 = Foo(1)
f3 = Foo(1)

print(f1.__dict__.items())
print(f1)
print(set([f1, f2, f3]))
print(len(set([f1, f2, f3])))

运行结果:
这里写图片描述
可见,当hash函数是如上写法时,具有相同属性的对象,就只会被加入集合中一次,因为他们的hash值是相同的。而且你可能会问,为什么不直接return hash(self.item),因为这样应付不了,当对象具有除了item以外的属性的这种情况。

posted @ 2018-06-30 19:39  allMayMight  阅读(94)  评论(0编辑  收藏  举报