在Python 3.5中进行select以在字典中比较它们时select键
在构build字典时如下所示:
dict = { True: 'yes', 1: 'No'} 当我在交互式Python解释器中运行它时,字典是这样表示的:
 dict = {True: 'No'} 
 我明白True和1的值是相同的,因为types强制,因为当比较数字types时,缩小的types被扩展为另一种types(布尔值是整数的子元素)。 所以我从文档中了解到,当我们inputTrue == 1 Python将True转换为1 ,并将它们进行比较。 
 我不明白的是为什么selectTrue作为一个关键而不是1 。 
我错过了什么?
字典是作为散列表实现的,在这里添加键/值有两个重要的概念: 散列和相等 。
为了插入特定的键/值,Python首先计算键的哈希值。 这个散列值用于确定Python应该首先尝试放置键/值的表的行。
如果散列表的行是空的,那么很好:新的键/值可以插入到字典中,填充空行。
 但是,如果该行中已经有东西,那么Python需要testing这些键是否相等。 如果键是相等的(使用== ),那么它们被认为是相同的键,Python只需要更新该行的相应值。 
(如果键不相等,Python会查看表中的其他行,直到find键或到达一个空行,但这与此问题无关。
 当你写{True: 'yes', 1: 'No'} ,你告诉Python创build一个新的字典,然后用两个键/值对填充它。 这些被处理从左到右: True: 'yes'然后1: 'No' 。 
 我们有hash(True)等于1. True的关键在第1行的哈希表和string'yes'是它的价值。 
 对于下一对,Python认为hash(1)也是1,因此会查看表的第1行。 有一些东西已经存在,所以现在Python检查键是否相等。 我们有1 == True所以1被认为是与True相同的键,所以它的对应值被改为string'No' 。 
 这导致一个字典有一个条目: {True: 'No'} 。 
如果您想要观察CPython 3.5的内核,看看在表面Python级别下创build一个字典,下面是更多的细节。
- 
Python代码 {True: 'yes', 1: 'No'}被parsing为令牌并提供给编译器。 鉴于语法,Python知道必须使用大括号内的值创build字典。 字节代码将四个值加载到虚拟机的堆栈(LOAD_CONST),然后生成字典(BUILD_MAP)。
- 
四个常数值按照它们被看到的顺序被推到栈顶: 'No' 1 'yes' True
- 
然后用参数 2调用操作码BUILD_MAP(Python计算两个键/值对)。 这个操作码负责实际上从堆栈上的项目创build字典。 它看起来像这样 :TARGET(BUILD_MAP) { int i; PyObject *map = _PyDict_NewPresized((Py_ssize_t)oparg); if (map == NULL) goto error; for (i = oparg; i > 0; i--) { int err; PyObject *key = PEEK(2*i); PyObject *value = PEEK(2*i - 1); err = PyDict_SetItem(map, key, value); if (err != 0) { Py_DECREF(map); goto error; } } while (oparg--) { Py_DECREF(POP()); Py_DECREF(POP()); } PUSH(map); DISPATCH(); }
这里的三个关键步骤如下:
- 
一个空的哈希表使用 _PyDict_NewPresized创build。 小字典(只有几个项目,比如2个)需要一个八行的表格。
- 
进入 for循环,从2开始(在这种情况下),并倒计数到0.PEEK(n)是一个macros指向堆栈中的第n个项目。 因此,在循环的第一个迭代中,我们将拥有
 PyObject *key = PEEK(2*2); /* item 4 down the stack */ PyObject *value = PEEK(2*2 - 1); /* item 3 down the stack */ 
 这意味着*key将是True并且在第一个循环中*value将是'yes' 。 在第二个将是1和'No' 。 
-  在每个循环中调用PyDict_SetItem以将当前*key和*value放入字典中。 这是你编写dictionary[key] = value时调用的函数。 它计算密钥的散列值,以计算散列表中首先查找的位置,然后根据需要将该密钥与该行上任何现有密钥(如上所述)进行比较。
 基本的前提是 – True , 1有相同的散列,并且彼此相等 – 这就是为什么它们不能在哈希表中分开的键(技术上具有相同哈希的不等对象可能 – 但散列冲突会降低性能)。 
 >>> True == 1 True >>> hash(1) 1 >>> hash(True) 1 
现在,我们来考虑一个字节码:
 import dis dis.dis("Dic = { True: 'yes', 1: 'No'}") 
这打印:
  0 LOAD_CONST 0 (True) 3 LOAD_CONST 1 ('yes') 6 LOAD_CONST 2 (1) 9 LOAD_CONST 3 ('No') 12 BUILD_MAP 2 15 STORE_NAME 0 (Dic) 18 LOAD_CONST 4 (None) 21 RETURN_VALUE 
 基本上会发生什么是dict文字被标记为键和值,并被推送到堆栈。 之后, BUILD_MAP 2两对(键,值)转换为字典。 
 最有可能的堆栈数据顺序(这似乎是由字典的BUILD_MAP决定的)和BUILD_MAP实现细节决定了生成的字典键和值。 
 似乎键值赋值按字面意义上的顺序完成。 赋值的行为与d[key] = value操作相同,所以基本上是: 
-  如果key不是字典(通过平等):添加key做字典
-  存储keyvalue
 给定{True: 'yes', 1: 'No'} : 
-  以{}开始
- 
加 (True, 'yes')-   True不是在dict  – > (True, hash(True))==(True, 1)是字典中的新键
-  更新键值为1值为'yes'
 
-   True不是在dict  – > 
- 
添加 (1, 'no')-   1是字典(1 == True) – >在字典中不需要新的键
-  更新键值等于1值(True),值为'no'
 
-   
 结果: {True: 'No'} 
正如我所评论的,我不知道这是否被Python规范所保证,或者如果它只是CPython实现定义的行为,在其他解释器实现中可能会有所不同。
  True和1是不同的对象,但它们都具有相同的值: 
 >>> True is 1 False >>> True == 1 True 
这与两个可能具有相同值的string类似,但存储在不同的存储位置:
 >>> x = str(12345) >>> y = str(12345) >>> x == y True >>> x is y False 
首先将一个项目添加到字典中; 那么当另一个被添加时, 该值已经存在作为一个关键 。 所以密钥更新,密钥值是唯一的。
 >>> {x: 1, y: 2} {"12345": 2} 
如果密钥已经存在于字典中,它不会覆盖仅与相关值相关的密钥。
 我相信写作x = {True:"a", 1:"b"}是: 
 x = {} x[True] = "a" x[1] = "b" 
 到达x[1] = "b"的时候,关键字True已经在字典中了,为什么要改变呢? 为什么不只是覆盖相关的值。 
sorting似乎是原因。 代码示例:
 >>> d = {True: 'true', 1: 'one'} >>> d {True: 'one'} >>> d = {1: 'one', True: 'true'} >>> d {1: 'true'} 
这是一个暧昧的声明。
 逻辑: d = { True: 'no', 1: 'yes'} 
当python评估expression式时,它是按顺序执行的,所以相当于这个。
 d = dict() d[True] = 'no' d[1] = 'yes' 
常量True是关键,但它的计算结果为1,所以你只需要将键的值设置为两次。