# ~bool deprecation

**URL:** <https://discuss.python.org/t/bool-deprecation/62232>\
**Category:** Core Development\
**Created:** [August 28, 2024, 6:49pm UTC](https://discuss.python.org/t/bool-deprecation/62232 "2024-08-28T18:49:37Z")\
**Posts on this page:** 20\
**Page:** 5

<div class="post-metadata">

**Author:** ![hwelch](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/hwelch/32/33920_2.png) [@hwelch](https://discuss.python.org/u/hwelch)\
**Post date:** [February 15, 2026, 4:07am UTC](https://discuss.python.org/t/bool-deprecation/62232/81 "2026-02-15T04:07:21Z")

</div>

> [@tim.one](#):
>
> bool is a subclass of int in Python, period.

I would say, beyond that, bool is specifically the ints 0 and 1 too. I’ve used that many times to hack string formatters by multiplying the string by a bool. Since it’s totally valid to multiply a string by 0 to mask it out.

Another reasonable example of something I’ve done before that relies on bool being 1/0:

```python
models: list[Model]

errors = len(models) - sum(m.valid() for m in models)

```

Which would fail if bool wasn’t 1 and 0

---

<div class="post-metadata">

**Author:** ![timhoffm](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/timhoffm/32/19468_2.png) [@timhoffm](https://discuss.python.org/u/timhoffm)\
**Post date:** [February 15, 2026, 10:45pm UTC](https://discuss.python.org/t/bool-deprecation/62232/82 "2026-02-15T22:45:23Z")

</div>

This is all valid interpretation and all of this will continue to work. The only thing that is removed is the ~ operation, specifically because it leads outside the 0, 1 space and that was was confusing to users.

---

<div class="post-metadata">

**Author:** ![tim.one](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/tim.one/32/282_2.png) [@tim.one](https://discuss.python.org/u/tim.one)\
**Post date:** [February 15, 2026, 11:07pm UTC](https://discuss.python.org/t/bool-deprecation/62232/83 "2026-02-15T23:07:15Z")

</div>

> [@timhoffm](#):
>
> The only thing that is removed is the ~ operation, specifically because it leads outside the 0, 1 space and that was was confusing to users.

Except lots of things “lead outside the 0, 1 space”. For example, this isn’t uncommon at all:

```python
num_true = sum(map(predicate, iterable))

```

As in, e.g.,

```python
>>> sum(map(lambda i: not i % 3, range(12)))
4

```

which counts 0, 3, 6, and 9. Given that bool is a subclass of int, “the surprise” is when bools _don’t_ act like ints.

IMO it wasn’t “broken” to begin with. What next? Will we also “deprecate”, e.g.,

```python
>>> True / True
1.0

```

? I understand why that too could be surprising to someone coming from, say, C++ – but they’re not using C++ then, and should learn the language they are using.

---

<div class="post-metadata">

**Author:** ![hwelch](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/hwelch/32/33920_2.png) [@hwelch](https://discuss.python.org/u/hwelch)\
**Post date:** [February 15, 2026, 11:16pm UTC](https://discuss.python.org/t/bool-deprecation/62232/84 "2026-02-15T23:16:43Z")

</div>

I only brought this up because I saw some discussion of `True` being mapped to `-1` on the GitHub discussion and wanted to make sure that these common situations were documented somewhere in all this.

And yes, this was mentioned before, but I don’t think “you shouldn’t do that” is really a good counter since this is something that anyone who spends some time using the language will probably end up abusing at some point, and it’s surprisingly difficult to find/debug if it was suddenly changed.

---

<div class="post-metadata">

**Author:** ![Rosuav](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/rosuav/32/3429_2.png) [@Rosuav](https://discuss.python.org/u/Rosuav)\
**Post date:** [February 16, 2026, 1:15am UTC](https://discuss.python.org/t/bool-deprecation/62232/85 "2026-02-16T01:15:20Z")

</div>

> [@hwelch](#):
>
> I only brought this up because I saw some discussion of `True` being mapped to `-1` on the GitHub discussion and wanted to make sure that these common situations were documented somewhere in all this.

I haven’t seen true be -1 since my days of BASIC programming… blast from the past.

---

<div class="post-metadata">

**Author:** ![timhoffm](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/timhoffm/32/19468_2.png) [@timhoffm](https://discuss.python.org/u/timhoffm)\
**Post date:** [February 16, 2026, 8:56am UTC](https://discuss.python.org/t/bool-deprecation/62232/86 "2026-02-16T08:56:14Z")

</div>

> [@tim.one](#):
>
> Except lots of things “lead outside the 0, 1 space”. For example, this isn’t uncommon at all:
> 
> ```python
> num_true = sum(map(predicate, iterable))
> 
> ```

The difference being that such cases are logically unambiguous and they solve a real problem.

In contrast the correct interpretation of ~bool depends on the fact that it’s an unsigned integer. It’s a fact that people are prone to getting this wrong and think ~True → False, ~False → True. This leads to real bugs because `if ~condition` is always true. Looking only at the first page of [Code search results · GitHub](https://github.com/search?q=%2Fif+%7E%5Cw%2B%2F+language%3APython+&type=code) approximately half of the entires exhibit this bug.

OTOH, I have yet to see a real-world use case for the actual mapping ~False → -1; ~True → -2. If such a case exists `~int(b)` can be used and IMHO would be the clearer communication of intent anyway.

That is the background. We can now decide. Do we opt for purity (bool is implemented as int and therefore you can invert its bit pattern) and tell people to RTFM. The world is a dangerous place and you must know what you’re doing. Or do we want to protect users from accidental misuse and disallow this action, which is formally possible, but not needed in practice.

> [@tim.one](#):
>
> What next?

Nothing next. This is a unique case: There are no other operations that are logically meaningful on int and bool, but yield different results. `True / True` and `sum` have no meaning in a pure bool world. The only reasonable interpretation is as numbers 0,1. In contrast ~ has logical ambiguity and the result depends on the underlying integer representation. Is it unsigned or signed, in case of unsigned how many bits?

---

<div class="post-metadata">

**Author:** ![peterc](https://avatars.discourse-cdn.com/v4/letter/p/f9ae1b/32.png) [@peterc](https://discuss.python.org/u/peterc)\
**Post date:** [February 16, 2026, 9:41am UTC](https://discuss.python.org/t/bool-deprecation/62232/87 "2026-02-16T09:41:00Z")

</div>

The real-world fear is that if `foo.f` is a function that with the documented signature `f(c: int) -> float`, if I use the otherwise reasonable pattern

```python
from foo import f

foo_len = sum(f(x > 0) for x in xs)

```

now this might crash if `foo.f` uses `~c` in it’s implementation. But as a user I’m not supposed to care about the implementation details of `f`.

So the big issue is not that `~bool` solves a real-world problem, but that prohibiting `~bool` beyond the static type-checker level introduces problems.\[1\]

* * *

In practice this hasn’t bitten me yet because `~int` is an uncommon operation.

I also thought the ship has sailed at this point. I’ve given my opinion, but there’s not much point in fighting about it anymore, because this is now a (planned?) Python feature.

* * *

1. Besides which, [~bool deprecation - #80 by tim.one](https://discuss.python.org/t/bool-deprecation/62232/80) did just demonstrate a specific usecase for ~bool.

---

<div class="post-metadata">

**Author:** ![Rosuav](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/rosuav/32/3429_2.png) [@Rosuav](https://discuss.python.org/u/Rosuav)\
**Post date:** [February 16, 2026, 9:42am UTC](https://discuss.python.org/t/bool-deprecation/62232/88 "2026-02-16T09:42:54Z")

</div>

> [@peterc](#):
>
> I also thought the ship has sailed at this point. I’ve given my opinion, but there’s not much point in fighting about it anymore, because this is now a (planned?) Python feature.

It doesn’t HAVE to have sailed; deprecations CAN be reversed. It all depends on who feels strongly enough among the core devs.

---

<div class="post-metadata">

**Author:** ![Paddy3118](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/paddy3118/32/1396_2.png) [@Paddy3118](https://discuss.python.org/u/Paddy3118)\
**Post date:** [February 16, 2026, 9:49am UTC](https://discuss.python.org/t/bool-deprecation/62232/89 "2026-02-16T09:49:10Z")

</div>

> [@timhoffm](#):
>
> In contrast the correct interpretation of ~bool depends on the fact that it’s an unsigned integer. It’s a fact that people are prone to getting this wrong and think ~True → False, ~False → True. This leads to real bugs because `if ~condition` is always true. Looking only at the first page of [Code search results · GitHub](https://github.com/search?q=%2Fif+%7E%5Cw%2B%2F+language%3APython+&type=code) approximately half of the entires exhibit this bug.

Then do we make it easier to understand the issue or do we remove the ability to create the issue? I am currently in favour of more instruction/explanation when mixing operators and types and keeping the ability to use bitwise operators on bools and explaining that bools are also ints which can lead to …

---

<div class="post-metadata">

**Author:** ![timhoffm](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/timhoffm/32/19468_2.png) [@timhoffm](https://discuss.python.org/u/timhoffm)\
**Post date:** [February 16, 2026, 10:11am UTC](https://discuss.python.org/t/bool-deprecation/62232/90 "2026-02-16T10:11:01Z")

</div>

> [@peterc](#):
>
> The real-world fear is that if `foo.f` is a function that with the documented signature `f(c: int) `

I acknowledge this topic. It’s a potential issue. How relevant that is in practice is to be seen. This is also why there is a long deprecation period set to 4 releases. We’re now to years in and I haven’t seen any complaints.

Deprecations _can_ always be reverted or extended, if there are good reasons. I’m not clear though what the process is and who decides that.

In the end, this is a trade-off: Either we leave an API that is prone to misuse and that leads to hidden errors (`if ~condition` will just silently not do what you want). Or we remove it, risking creating clear errors in very rare valid use cases, that can easily be worked around by an explicit `int()` cast.

---

<div class="post-metadata">

**Author:** ![timhoffm](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/timhoffm/32/19468_2.png) [@timhoffm](https://discuss.python.org/u/timhoffm)\
**Post date:** [February 16, 2026, 10:14am UTC](https://discuss.python.org/t/bool-deprecation/62232/91 "2026-02-16T10:14:27Z")

</div>

> [@Paddy3118](#):
>
> I am currently in favour of more instruction/explanation when mixing operators

Improving documentation is always nice, but I doubt that will significantly reduce misuse. Only few users will read the documentation to that level of detail.

---

<div class="post-metadata">

**Author:** ![Paddy3118](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/paddy3118/32/1396_2.png) [@Paddy3118](https://discuss.python.org/u/Paddy3118)\
**Post date:** [February 16, 2026, 10:40am UTC](https://discuss.python.org/t/bool-deprecation/62232/92 "2026-02-16T10:40:21Z")

</div>

> [@timhoffm](#):
>
> Only few users will read the documentation to that level of detail.

Possibly, but removing the capability might make the operators _ **less** _ easy to learn. If we have the True/False to 1/0 automatic conversion when bools are used in an int context, then the implications need to be understood, and maybe this particular case should be highlighted in a more general discussion. I remember that “Bools are not ints, they have representations and conversions in each type that are useful though”.

---

<div class="post-metadata">

**Author:** ![Stefan2](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/stefan2/32/18492_2.png) [@Stefan2](https://discuss.python.org/u/Stefan2)\
**Post date:** [February 16, 2026, 11:34am UTC](https://discuss.python.org/t/bool-deprecation/62232/93 "2026-02-16T11:34:22Z")

</div>

> [@timhoffm](#):
>
> We’re now to years in and I haven’t seen any complaints.

That’s not true. You’ve seen [mine](https://github.com/python/cpython/pull/103487#issuecomment-2028749940) (and I think also some others).

---

<div class="post-metadata">

**Author:** ![timhoffm](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/timhoffm/32/19468_2.png) [@timhoffm](https://discuss.python.org/u/timhoffm)\
**Post date:** [February 16, 2026, 12:25pm UTC](https://discuss.python.org/t/bool-deprecation/62232/94 "2026-02-16T12:25:43Z")

</div>

Sorry, you are right. I had forgotten this. There may be a low single digit number. I suggest we collect these cases in a single place, so that they don’t get lost. I’ve created [Real world impediments through ~bool deprecation](https://discuss.python.org/t/real-world-impediments-through-bool-deprecation/106171) for this.

---

<div class="post-metadata">

**Author:** ![guido](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/guido/32/21_2.png) [@guido](https://discuss.python.org/u/guido)\
**Post date:** [February 16, 2026, 12:42pm UTC](https://discuss.python.org/t/bool-deprecation/62232/95 "2026-02-16T12:42:55Z")

</div>

I cry when I read this debate.

The inconsistency of disallowing ~x when x is a bool while allowing it when x is an int trumps the lack of a use case here.

Arithmetic is hard. Let’s not make it harder to accommodate people coming from some other languages.

---

<div class="post-metadata">

**Author:** ![timhoffm](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/timhoffm/32/19468_2.png) [@timhoffm](https://discuss.python.org/u/timhoffm)\
**Post date:** [February 16, 2026, 1:17pm UTC](https://discuss.python.org/t/bool-deprecation/62232/96 "2026-02-16T13:17:13Z")

</div>

Do I understand your comment correctly that you are opposed to the bool deprecation? You were originally the one encouraging turning the proposal into a PR in [bool(~True) == True · Issue #82012 · python/cpython · GitHub](https://github.com/python/cpython/issues/82012#issuecomment-1258708393).

To be clear: Reconsideration is ok. Maybe we are now smarter than back then. If you (and maybe the PR approvers) as proponents of the change think it’s not a good idea anymore, I won’t insist.

---

<div class="post-metadata">

**Author:** ![guido](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/guido/32/21_2.png) [@guido](https://discuss.python.org/u/guido)\
**Post date:** [February 16, 2026, 1:40pm UTC](https://discuss.python.org/t/bool-deprecation/62232/97 "2026-02-16T13:40:12Z")

</div>

Right, I’ve changed my mind. Or maybe I wasn’t thinking far enough ahead at the time.

I would be okay if `~b` where `b` is statically typed as `bool` might trigger a warning in linters or static type checkers.

---

<div class="post-metadata">

**Author:** ![tim.one](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/tim.one/32/282_2.png) [@tim.one](https://discuss.python.org/u/tim.one)\
**Post date:** [February 16, 2026, 6:30pm UTC](https://discuss.python.org/t/bool-deprecation/62232/98 "2026-02-16T18:30:16Z")

</div>

> [@timhoffm](#):
>
> . In contrast ~ has logical ambiguity and the result depends on the underlying integer representation. Is it unsigned or signed, in case of unsigned how many bits?

Defined by the language; implementations have no choices here. However they implement it, they must create the illusion that ints are represented in 2’s-complement with an “infinite number” of sign bits.

```python
>>> ~True == -2
... DeprecationWarning elided ...
True
>>> ~False == -1
... DeprecationWarning elided ...
True

```

Those must be true under all Python implementations, as also are things like `-2 & 7 == 6`. Every bit is defined. The actual representation isn’t exposed. For example, CPython happens to store ints as an absolute value plus a distinct “sign” bit, but that’s invisible at the language level.

People mistakenly using “~” for logical “not” have deeper conceptual gaps than a deprecation warning can fill 😉

---

<div class="post-metadata">

**Author:** ![h-vetinari](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/h-vetinari/32/1220_2.png) [@h-vetinari](https://discuss.python.org/u/h-vetinari)\
**Post date:** [February 16, 2026, 11:21pm UTC](https://discuss.python.org/t/bool-deprecation/62232/99 "2026-02-16T23:21:54Z")

</div>

> [@tim.one](#):
>
> People mistakenly using “~” for logical “not” have deeper conceptual gaps than a deprecation warning can fill 😉

That’s a tad facetious, as “`~` for logical not” has been popularized enormously for just that purpose by numpy, pandas, etc. The distinction being that it only works for arrays, but it’s hardly a stretch for users to want to try this as general boolean negation.

---

<div class="post-metadata">

**Author:** ![Rosuav](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/rosuav/32/3429_2.png) [@Rosuav](https://discuss.python.org/u/Rosuav)\
**Post date:** [February 16, 2026, 11:22pm UTC](https://discuss.python.org/t/bool-deprecation/62232/100 "2026-02-16T23:22:57Z")

</div>

> [@h-vetinari](#):
>
> as “`~` for logical not” has been popularized enormously for just that purpose by numpy, pandas, etc. The distinction being that it only works for arrays

An array full of bools has a lot of similarity to an integer full of bits, though. When you negate the array, you’re flipping each individual bit.

[Previous page](https://discuss.python.org/t/bool-deprecation/62232.md?page=4)

[Next page](https://discuss.python.org/t/bool-deprecation/62232.md?page=6)
