V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
banxi1988
V2EX  ›  Python

Python中Set集合中对象的__hash__的问题

  •  
  •   banxi1988 ·
    banxi1988 · 2013-09-05 20:07:31 +08:00 · 6477 次点击
    这是一个创建于 4098 天前的主题,其中的信息可能已经有所发展或是发生改变。
    今天测试了下实现set相减的demo。
    我发现必须要实现__hash__这个magic方法才可以,但是呢?
    感觉又不需要对对象的所以字段都进行hash,如我下面的代码,就可以。
    因为set判断元素相等是用__eq__这个magic方法的。那么,我的问题就是,
    像我下面的Person对象的__hash__没有对addrs这个进行hash这会有什么问题吗?

    9 条回复    1970-01-01 08:00:00 +08:00
    yaroot
        1
    yaroot  
       2013-09-05 20:34:44 +08:00
    摘自文档: A set object is an unordered collection of distinct hashable objects.
    keakon
        2
    keakon  
       2013-09-05 20:35:08 +08:00
    性能从 O(1) 下降到 O(n)
    banxi1988
        3
    banxi1988  
    OP
       2013-09-05 21:21:40 +08:00
    @keakon 请指教,怎么回到O(1)。
    banxi1988
        4
    banxi1988  
    OP
       2013-09-05 21:23:02 +08:00
    @yaroot 你是让我实现__hash__的时候,对可能影响相等判断的值都进行hash吗?
    yaroot
        5
    yaroot  
       2013-09-05 21:29:33 +08:00
    @banxi1988 不是我想, 你 print len({ p1, p2, p3, p4, p5 }) 看看
    banxi1988
        6
    banxi1988  
    OP
       2013-09-05 21:33:45 +08:00
    @yaroot print("set len",len({p1,p2,p3,p4,p5})) #output:('set len', 2)
    然后呢?
    banxi1988
        7
    banxi1988  
    OP
       2013-09-05 21:53:38 +08:00
    @keakon
    我对__hash__时是否对addrs进行hash进行简单的测试,显然是不进行__hash__来得快:
    对比如下:
    def __hash__(self):
    # saddrs = sorted(self.addrs, key=lambda addr:addr.name)
    # addrs_str = ''.join([addr.name for addr in saddrs])
    return hash((self.name,self.sex))

    对addrs进行hashed,构造及比较部分需要的时间:
    # with addr hashed ('time=', 4.042909860610962)
    不hash时花的时间:
    # without addr hashed ('time=', 2.322601795196533)
    这样看来不对addrs进行hash是正确的选择喽。那hash用来做什么呢?

    @yaroot
    yaroot
        8
    yaroot  
       2013-09-05 23:03:07 +08:00   ❤️ 1
    @banxi1988

    http://docs.python.org/2/reference/datamodel.html#object.__hash__
    http://docs.python.org/2/glossary.html#term-hashable
    被误导了下....但我觉得还是按照文档来实现比较好, 虽然set用__eq__的..

    但是按文档这样也会产生冲突, 都是mutable object, 除非你都当它们是immutable的..
    这个还是看你实际需求吧...性能瓶颈一般不会在这里
    banxi1988
        9
    banxi1988  
    OP
       2013-09-06 12:31:04 +08:00
    @yaroot 嗯,这样看来,我这样实现也没有什么大的问题,
    同样的hash值的对象才会去使用__eq__比较。谢谢
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   928 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 19:52 · PVG 03:52 · LAX 11:52 · JFK 14:52
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.