classification
Title: Better document mixed-type comparison of set items, dict keys
Type: behavior Stage:
Components: Documentation Versions: Python 3.6
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: docs@python Nosy List: Janusz Harkot, docs@python, mark.dickinson, terry.reedy, tim.peters
Priority: normal Keywords:

Created on 2018-05-18 15:19 by Janusz Harkot, last changed 2018-05-18 19:44 by terry.reedy.

Messages (6)
msg317032 - (view) Author: Janusz Harkot (Janusz Harkot) Date: 2018-05-18 15:19
using boolean (True/False) as dictionary keys, coerce them to integers - is this behavior documented somewhere?

I know that asking to fix this is not easy fix, but shouldn't this be highlighted everywhere with red flags and warnings, so people will know that this is expected?


Python 3.6.5 (default, Mar 29 2018, 03:28:50)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> dta = {False: 'false', True: 'true', 0: 'zero', 1: 'one'}
>>> print(dta[False])
zero
>>>
msg317033 - (view) Author: Janusz Harkot (Janusz Harkot) Date: 2018-05-18 15:22
Python 3.6.5 (default, Mar 29 2018, 03:28:50)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> dta = {False: 'false', True: 'true', 0: 'zero', 1: 'one'}
>>> print(dta[False])
zero
>>> dta
{False: 'zero', True: 'one'}
>>>
msg317035 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2018-05-18 15:26
It's documented here: https://docs.python.org/3/library/stdtypes.html#mapping-types-dict

> Numeric types used for keys obey the normal rules for numeric
> comparison: if two numbers compare equal (such as 1 and 1.0) then 
> they can be used interchangeably to index the same dictionary entry.

Since False == 0, False and 0 are interchangeable as dictionary keys. Similarly for True and 1. Note that the dictionary you created only actually has two entries:

>>> dta = {False: 'false', True: 'true', 0: 'zero', 1: 'one'}
>>> dta
{False: 'zero', True: 'one'}

Though calling out numeric types in particular in the docs does feel a little odd to me: the rule is that *any* two hashable objects that compare equal should be interchangeable for the purposes of dictionary lookup (or set membership, come to that). There's nothing particularly special about numbers in this context.
msg317045 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2018-05-18 18:13
Mark, are you suggesting a doc addition (and a change of Components) or should we close this as 'not a bug'?
msg317046 - (view) Author: Tim Peters (tim.peters) * (Python committer) Date: 2018-05-18 18:29
I expect these docs date back to when ints, longs, and floats were the only hashable language-supplied types for which mixed-type comparison could ever return True.

They could stand some updates ;-)  `fractions.Fraction` and `decimal.Decimal` are more language-supplied numeric types that participate now, and the Boolean singletons are instances of (a subclass of) `int`.  I think it would be good to point that out, especially the latter (in many other languages Booleans can't be compared to ints).

So +1 both to Mark's more-general explanation, and to explicitly naming more specific cases for illustration.
msg317053 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2018-05-18 19:44
With Tim's addition

>>> from fractions import Fraction as F
>>> from decimal import Decimal as D
>>> s = {0, 1, 0.0, 1.0, F(0,1), F(1, 1), D(0), D(1), False, True}
>>> s
{0, 1}

I think we should consider moving the main discussion of the general comparison and hashing principle and example to the set entry.  (Sets ars simpler and are when people new to Python already know about.) Point out that for displays, the first of equals is kept and not replaced (this is also true of dicts).  Then, in the dict entry, say that dict keys are treated like set items, give an equivalent dict example, and link to the discussion of set items.

>>> x = None
>>> d = {0:x, 1:x, 0.0:x, 1.0:x, F(0,1):x, F(1, 1):x, D(0):x, D(1):x, False:x, True:x}
>>> d
{0: None, 1: None}
>>>
History
Date User Action Args
2018-05-18 19:44:10terry.reedysetmessages: + msg317053
title: False/True as dictionary keys treated as integers -> Better document mixed-type comparison of set items, dict keys
2018-05-18 19:21:44terry.reedysetassignee: docs@python

components: + Documentation, - Interpreter Core
nosy: + docs@python
2018-05-18 18:29:27tim.peterssetnosy: + tim.peters
messages: + msg317046
2018-05-18 18:13:21terry.reedysetnosy: + terry.reedy
messages: + msg317045
2018-05-18 15:26:48mark.dickinsonsetnosy: + mark.dickinson
messages: + msg317035
2018-05-18 15:22:01Janusz Harkotsetmessages: + msg317033
2018-05-18 15:19:50Janusz Harkotcreate