Repository navigation
bool(~True) == True #82012
Description
Activity
Bitwise operators have inconsistent behavior when acting on bool values: (Python 3.7.4)
# "&" works like "and" >>> True & True True >>> True & False False >>> False & False False # "|" works like "or" >>> True | True True >>> True | False True >>> False | False False # "~" does not work like "not"! >>> ~True -2 >>> ~False -1
The result of this is the a user might start working with "&" and "|" on bool values (for whatever reason) and it will work as expected. But then, when adding "~" to the mix, things start to break.
The proposal is to make "~" act like "not" on bool values, i.e. ~True will be False; ~False will be True.
I'm not sure if this has any negative impact on existing code. I don't expect any, but you can never know. If there is no objection to this change, I can even try to implement it myself an submit a patch.
- added3.7 (EOL)end of lifeend of lifeinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)type-featureA feature request or enhancementA feature request or enhancement
on Aug 12, 2019 For instances of
int,~does bitwise negation (with the usual two's-complement with an infinite number of bits model that Python uses for all bitwise operations on arbitrary-precision integers).And rightly or wrongly,
TrueandFalseare instances ofint, so it should be possible to useTruealmost anywhere you'd usually use1, with no change in behaviour. The proposed change would give usTrue == 1but~True != ~1.So I think we're stuck with the current behaviour.
Given a time machine, this could arguably be "fixed" by making
Trueequal to-1rather than1... But absent that time machine, I'd expect some amount of breakage from the proposed change.It's worth noting that NumPy's
bool_type does do this:>>> import numpy as np >>> ~np.bool_(True) False >>> ~np.bool_(False) True
But
np.bool_doesn't have the same "is-a" relationship with integers:>>> np.bool_.__mro__ (<class 'numpy.bool_'>, <class 'numpy.generic'>, <class 'object'>)IOW, -1 from me.
Looks like this is essentially a duplicate of bpo-12447
+0 This proposal may be worth re-considering. I've seen the problem arise in practice on multiple occasions. I suspect that it will continue to give people trouble.
Right now, a bool is-a int that 1) only has two singleton instances equal to zero and one, 2) has a different repr, and 3) has the & | and ^ operations redefined to return instances of bool.
I think we could also override the ~ operation. That would be a Liskov violation, making bools slightly less substitutable for ints, but it does so in a way that is intuitive and likely to match what a user intends when inverting a bool.
See also the discussion started by Antoine here:
https://mail.python.org/pipermail//python-ideas/2016-April/039488.html
-1 from me too.
Making True == -1 looks interesting, but it has drawbacks.
Making True == -1 looks interesting, but it has drawbacks.
Yes, please ignore that part of my post. :-) It shouldn't be considered seriously until a time machine turns up (and probably not even then).
My main worry with the proposed change is accidental breakage from the change in meaning. I've so far failed to find any examples of real-world functions that could/would be broken - the closest I've come is floating-point bit-pattern manipulation functions (constructing a bit-string from a sign, exponent and significand, where it's quite natural to treat the sign both as an "is_negative" boolean and as a 0-or-1 integer). But that case didn't involve a
~signat any point, so it doesn't count.Still, I have a nagging suspicion that such a function will turn up if we make this change.
Having ~True *not* be the same as ~1 feels like a bigger surprise to me than having ~True not be False; it breaks my simple mental model that bools always behave like ints in numeric contexts.
There's also the minor annoyance that there isn't currently an obvious safe way to convert an integer-like thing to an actual int, to make sure that bools do the right thing in a numeric context. operator.index *ought* to be that obvious way, but it leaves bools untouched.
>>> operator.index(True) TrueMark, isn't
int()the obvious way "to convert an integer-like thing to an actual int"?>>> int(True) 1 >>> int(False) 0
For the rest, I'm -True on making ~ do something magical for bools inconsistent with what it does for ints. "is-a" is a promise.
Reacted by Doug HoskissonFor reference, the link to the Python-Ideas discussion in Mailman 3:
21 remaining items
- added3.12only security fixesonly security fixesand removed3.7 (EOL)end of lifeend of life
on Sep 28, 2022 @timhoffm The deadline for getting this into 3.12 is in about a month.
Thanks for the reminder. I may get around this next week.
@iritkatriel the PR #103487 is ready. Can I still help with anything to get this into 3.12?
- added 5 commits that reference this issue
on Apr 28, 2023 - added a commit that references this issue
on May 3, 2023 I don't think I understand why anyone would want to use | and & on bools to get another bool, instead of just using
orandand.I think I've had cases where I wanted a bool and needed both operands evaluated, so
orandandwouldn't have worked.- added a commit that references this issue
on May 30, 2024 Futher discussion: https://discuss.python.org/t/bool-deprecation/62232
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
Linked PRs