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
firejoke
V2EX  ›  Python

问个神奇的问题

  •  
  •   firejoke · 2018-07-03 19:43:06 +08:00 · 2996 次点击
    这是一个创建于 2320 天前的主题,其中的信息可能已经有所发展或是发生改变。
    d = {str(x):y for x,y in enumerate([x for x in range(100)])}
    为什么每次遍历同一个字典,
    其输出顺序都是一样的,
    不论是在 2.x 版本,还是 3.6 以下或是 3.6 以上
    15 条回复    2018-07-06 22:12:06 +08:00
    frostming
        1
    frostming  
       2018-07-03 20:08:32 +08:00
    不懂你什么意思,d 构造好了之后,遍历顺序当然是一定的了,都是乱的。
    Python3.6 改进之处在于,它保证 d 的顺序和插入顺序一致。
    20015jjw
        2
    20015jjw  
       2018-07-04 02:19:17 +08:00 via Android
    lz 是不是要重新想想他是怎么读的..
    firejoke
        3
    firejoke  
    OP
       2018-07-04 08:47:55 +08:00
    @frostming 是说,dict 构造好后,其遍历顺序是已经决定好了的?根据 hash 值?
    firejoke
        4
    firejoke  
    OP
       2018-07-04 08:49:28 +08:00
    @20015jjw 是的......,确实以前从没想过......,我是面向问题型的: )嘻嘻~
    frostming
        5
    frostming  
       2018-07-04 08:55:21 +08:00
    @firejoke 是的
    Marmot
        6
    Marmot  
       2018-07-04 10:27:46 +08:00
    <=3.5 的不是有序字典,3.6 是有序字典,3.7 我还没有看
    Raymon111111
        7
    Raymon111111  
       2018-07-04 10:58:00 +08:00
    看看底层究竟是怎么存的就明白了
    araraloren
        8
    araraloren  
       2018-07-04 11:45:58 +08:00
    xiaket
        9
    xiaket  
       2018-07-04 12:23:12 +08:00
    3.6 就已经将字典序作为特性添加到文档了, 这个特性后面应该不会再折腾了.
    tkmiles
        10
    tkmiles  
       2018-07-04 14:01:03 +08:00
    底层来说, dict 是用储 kv 的是一个数组, 可以称为数据数组, 数组里面的每一个元素都存储了 key/value 对象
    [{key: key_object, value: value_object}, ...]

    3.6 存实现的话, hash 表和数据数组是分开的(这里 hash 可以当做数组好理解, 实际实现是一个共用体, 更具体的请去看源码)
    插入的时候总是 append 到数据数组, 每次遍历的时候, 都是遍历这个数据数组, 所以, 3.6+都是插入顺序
    至于删除什么的, 是另外一个话题了

    然后 2.x 的话, 数据数组和 hash 表是一个数组, 所以插入的时候是按 hash 值插入(当然是二次散列)
    所以, 遍历的时候就是遍历 hash 表(也可以说是数据数组), 那就是按 hash 顺序返回
    tkmiles
        11
    tkmiles  
       2018-07-04 14:05:22 +08:00
    具体到你的例子, 因为整数的 hash 是自己的值(当然整数的 hash 不一定是自己, 这就是另外一个话题了)
    所以 1 到 100 中自然不管是 hash 顺序还是插入顺序, 都是 1, 2, 3, 4, ... 这样的顺序

    你可以实践一下

    x={'b': 'b', 1: 1}在 3.6 和 2.x 下, 打印 keys 的区别, 注意一下, python3.6 下 ipython 打印有问题, 请使用
    print(x.keys())而不是 print(x)
    frostming
        12
    frostming  
       2018-07-04 15:17:47 +08:00
    @xiaket 3.6 就已经是有序的了,但是作为字典实现的副作用隐式加入的
    3.7 已经加入 release note 作为正式特性了,也就是说代码可以依靠这个特性了。
    lunaticus7
        13
    lunaticus7  
       2018-07-04 18:43:08 +08:00
    字典遍历保序,在 py3.6 以前,只是 CPython (最常用的 python 解释器)的实现特性,并非语言特性。py3.6 后变成了语言特性。
    firejoke
        14
    firejoke  
    OP
       2018-07-05 09:05:49 +08:00
    @araraloren 看楼下的回复,貌似是的
    @tkmiles 基础扎实!我在 ipython 下都是直接 k,v 不加 print()

    @lunaticus7 也算是 py 的进步吧
    firejoke
        15
    firejoke  
    OP
       2018-07-06 22:12:06 +08:00 via iPhone
    @tkmiles 抱歉,我记错了,我是在 cpython 下用 k,v
    不是 ipython
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2681 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 94ms · UTC 01:45 · PVG 09:45 · LAX 17:45 · JFK 20:45
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.