zoukankan      html  css  js  c++  java
  • Python中hash的问题

    ref:http://heipark.iteye.com/blog/1743819

    在下面这个例子里:

    class Item(object):  
      
        def __init__(self, foo, bar):  
            self.foo = foo  
            self.bar = bar  
          
        def __repr__(self):  
            return "Item(%s, %s)" % (self.foo, self.bar)  
          
    print set([Item('1', '2'), Item('1', '2')])  
      
    # 输出: set([Item(1, 2), Item(1, 2)]) 

    逻辑上讲,set中的两个对象是貌似相同的,那么set中应该只有一个对象

    实际上不是这样

    set是根据两个元素的hash value判断这两个对象是不是相同的。元素的hash value是通过hash方法得到的(内部__hash__() magic method)。

    根据文档:

    All of Python’s immutable built-in objects are hashable; mutable containers (such as lists or dictionaries) are not. Objects which are instances of user-defined classes are hashable by default. They all compare unequal (except with themselves), and their hash value is derived from their id().

    可知道只有非可变对象才可hash,并且instances of user-defined classes的hash value是根据他们的id得到的。这个id(ref:https://docs.python.org/3/library/functions.html#id),可以理解为对象在内存中的地址,所以例子里的输出就不奇怪了

    关于__hash__()的自定义实现,文档(ref:https://docs.python.org/3/reference/datamodel.html#object.__hash__)是这么说的:

    it is advised to mix together the hash values of the components of the object that also play a part in comparison of objects by packing them into a tuple and hashing the tuple.

    并且举了一个例子:

    def __hash__(self):
        return hash((self.name, self.nick, self.color))

    这里再引入一个概念:hashable,文档是这么写得:

    An object is hashable if it has a hash value which never changes during its lifetime (it needs a __hash__() method), and can be compared to other objects (it needs an __eq__() method). Hashable objects which compare equal must have the same hash value.

    简单来说,hashable的对象必须实现__hash__ and __equal__两个方法

    我们之前说过了hash方法怎么实现,但是仅仅实现hash方法,是不能让刚开始的例子中输出正确的结果的。原因如下(ref:https://docs.python.org/3/reference/datamodel.html#object.__hash__):

    If a class does not define an __eq__() method it should not define a __hash__() operation either; if it defines __eq__() but not __hash__(), its instances will not be usable as items in hashable collections. If a class defines mutable objects and implements an __eq__() method, it should not implement __hash__(), since the implementation of hashable collections requires that a key’s hash value is immutable (if the object’s hash value changes, it will be in the wrong hash bucket).

    如果定义了eq,没有定义hash,那么显然,由于hash value不同,刚开始的例子中输出结果是错误的

    定义hash的同时要定义eq

    之所以要定义eq,是为了处理set中有两个对象的hash value相同,这时候要怎样处理。

    eq不是每次把元素放进set里都要调用的。如果某个元素和set中的已有元素的hash value都不同,那就没有调用eq的必要了。如果即使两个元素的hash value不同,也要调用eq的话,就失去了hash的意义

    所以在刚开始的例子里加上:

        ...
        def __eq__(self, other):  
            if isinstance(other, Item):  
                return ((self.foo == other.foo) and (self.bar == other.bar))  
            else:  
                return False  
          
        def __hash__(self):  
            return hash(self.foo + " " + self.bar) 
        ...

    就ok了

  • 相关阅读:
    安卓使用spinner控件和pull解析实现全国省市县的三级联动(附上xml文件)
    安卓linearlayout布局的一个嵌套实例
    接口回调的例子和安卓中的接口回掉实例
    Android Studio 快捷键
    java比较器 之compareable 和comparato比较
    4.Gradle构建Spring Boot项目
    2.Gradle安装和常用命令
    1.Gradle基础介绍
    6.SpringBoot学习(六)——Spring Boot Banner自定义
    4.SpringBoot学习(四)——Spring Boot Validation校验及原理
  • 原文地址:https://www.cnblogs.com/geeklove01/p/Python.html
Copyright © 2011-2022 走看看