This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Truth value of sets not properly documented
Type: enhancement Stage: resolved
Components: Documentation Versions: Python 3.7, Python 3.6, Python 3.5
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: terry.reedy Nosy List: docs@python, rhettinger, terry.reedy, thomassen
Priority: low Keywords:

Created on 2017-06-29 13:36 by thomassen, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 2508 merged python-dev, 2017-06-30 11:02
PR 2946 merged terry.reedy, 2017-07-29 19:21
Messages (9)
msg297268 - (view) Author: Peter Thomassen (thomassen) * Date: 2017-06-29 13:36
The truth value of sets is not properly documented, in particular regarding whether an empty set is considered false or not.

Ignoring primitive (such as numerals) as well as user-defined types, https://docs.python.org/3/library/stdtypes.html#truth says:

> The following values are considered false:
> 
> - [...]
> - any empty sequence, for example, '', (), [].
> - any empty mapping, for example, {}.
> - [...]
> 
> All other values are considered true

According to https://docs.python.org/3/library/stdtypes.html#sequence-types-list-tuple-range, a set is not a sequence (it is unordered, its elements do not have indices, etc.):

> There are three basic sequence types: lists, tuples, and range objects.

And, according to https://docs.python.org/3/library/stdtypes.html#mapping-types-dict,

> There is currently only one standard mapping type, the dictionary.

So, as per the documentation, the set type is not a type that can ever be False. However, when I try, bool(set()) evaluates to False.

When I asked this on Stack Overflow, someone checked in the CPython code and judged that this is most likely a mere documentation issue: https://stackoverflow.com/a/44813565/6867099
msg297312 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2017-06-29 20:19
This case was supposed to be covered by the last bullet point, "instances of user-defined classes, if the class defines a __bool__() or __len__() method, when that method returns the integer zero or bool value False.".  The word "user-defined" should be dropped.

Also, the whole section can be simplified to something like:

"""
By default, objects are considered true unless they define either a __bool__ method that returns False or __len__ method that returns zero.  

Practically, this means that empty containers are false (such as [], (), {}, '', etc) and that numbers equal to zero are false (such as 0, 0.0, 0.0j, False, Decimal(0), Fractions(0, 1), etc).  Also, *None* is a false value.


"""
msg297391 - (view) Author: Peter Thomassen (thomassen) * Date: 2017-06-30 11:19
I submitted a PR on github, and signed the CLA before doing so. (I double-checked my bpo username in the CLA, and my github username in the bpo profile.) Still, the bot says I need to sign the CLA. I'm not sure what to do?
msg297448 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2017-06-30 22:14
1. You have to go to your profile page
https://bugs.python.org/user26480
and add your GitHub name in the GitHub Name box.
2. A committer has to change the labels to trigger the robot to recheck.  I did that but it did not work because of 1.

As I said in my review, I strongly prefer leaving the bulleted list and making a minimal addition of 'set or' and 'set(), '.  I would not merge the current patch.
msg298099 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2017-07-11 02:03
Responding here to Peter's PR comment.  Peter opened this issue with the claim that the doc failed a specific test case-- document the truth value of set().  Since mappings are (or can be viewed as) a specialized type of set, I always considered that the empty mapping line implicitly covered sets.  But I acknowledge that this is not clear for everyone.  The simplest fix to make the test pass would be: "any unordered collection, for example, set(), {}".  This should also cover frozenset and a possible frozendict.

Raymond noted that 'user-defined' in the last bullet point is wrong (it implies that built-in functions are different) and should be deleted.  He then combined the corrected rule for false with the default rule in the next sentence to produce a succinct statement of the actual rule.  (In CPython, 'default' is literally true. Class 'object' has neither __bool__ nor __len__; ditto for all subclasses that do not add one.)

With a minor change, I like this statement and agree that it should be moved above the examples.  But I think the bullet points should be reduced to just 3, rewritten, and single spaced, but not smashed into running text.  I suggest replacing everything between the first sentence (ending with 'below.') and the last two (beginning with 'Operations') with:

"By default, an object is considered true unless its class defines either a __bool__ method that returns False or __len__ method that returns zero, when called with the object.  Here are most of the built-in objects considered false.

* constants defined to be false: None and False.
* numeric 0 of any type: 0, 0.0, Decimal(0), Fractions(0, 1)
* empty sequences and collections: '', (), [], {}, set(), range(0)
"

Before writing the above, I checked that an instance attribute __bool__ = lambda: False is not consulted by bool().
msg298327 - (view) Author: Peter Thomassen (thomassen) * Date: 2017-07-14 01:13
I like your most recent suggestion, and updated the PR after fixing a typo ('Fractions') and making it more complete (complex numbers).

Let me know if anything else is needed.

(A mapping is not a specialized set, at least as far as typing is concerned: `isinstance({}, set)` is false. Semantically, they may be related, but the question here is whether the types are actually related.)
msg298335 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2017-07-14 04:13
Raymond, if you either unassign yourself or approve the current PR, I will merge and backport to 3.6 (but not 3.5).
msg299483 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2017-07-29 19:18
New changeset caa1280d1ee5f828f346b585169a7592371d3faa by Terry Jan Reedy (Peter Thomassen) in branch 'master':
bpo-30803: clarify truth value testing documentation (#2508)
https://github.com/python/cpython/commit/caa1280d1ee5f828f346b585169a7592371d3faa
msg299488 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2017-07-29 22:56
New changeset 4c7b368de7bcabdd821059c023c46c9d85668d3f by Terry Jan Reedy in branch '3.6':
[3.6] bpo-30803: clarify truth value testing documentation (GH-2508) (#2946)
https://github.com/python/cpython/commit/4c7b368de7bcabdd821059c023c46c9d85668d3f
History
Date User Action Args
2022-04-11 14:58:48adminsetgithub: 74986
2017-07-29 22:56:58terry.reedysetstatus: open -> closed
2017-07-29 22:56:48terry.reedysetresolution: fixed
stage: resolved
2017-07-29 22:56:08terry.reedysetmessages: + msg299488
2017-07-29 19:21:59terry.reedysetpull_requests: + pull_request2995
2017-07-29 19:18:15terry.reedysetmessages: + msg299483
2017-07-21 15:24:03rhettingersetassignee: rhettinger -> terry.reedy
2017-07-14 04:13:39terry.reedysetmessages: + msg298335
2017-07-14 01:13:23thomassensetmessages: + msg298327
2017-07-11 02:03:20terry.reedysetmessages: + msg298099
2017-06-30 22:14:48terry.reedysetnosy: + terry.reedy
messages: + msg297448
2017-06-30 11:19:46thomassensetmessages: + msg297391
2017-06-30 11:02:56python-devsetpull_requests: + pull_request2579
2017-06-29 20:19:15rhettingersetpriority: normal -> low

nosy: + rhettinger
messages: + msg297312

assignee: docs@python -> rhettinger
2017-06-29 13:36:18thomassencreate