mirror of
https://github.com/python/cpython
synced 2024-10-14 09:58:30 +00:00
gh-82012: Deprecate bitwise inversion (~) of bool (#103487)
The bitwise inversion operator on bool returns the bitwise inversion of the underlying int value; i.e. `~True == -2` such that `bool(~True) == True`. It's a common pitfall that users mistake `~` as negation operator and actually want `not`. Supporting `~` is an artifact of bool inheriting from int. Since there is no real use-case for the current behavior, let's deprecate `~` on bool and later raise an error. This removes a potential source errors for users. Full reasoning: https://github.com/python/cpython/issues/82012#issuecomment-1258705971 Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com> Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com>
This commit is contained in:
parent
5b05b013ff
commit
fdb3ef8c0f
|
@ -147,7 +147,7 @@ are always available. They are listed here in alphabetical order.
|
|||
or omitted, this returns ``False``; otherwise, it returns ``True``. The
|
||||
:class:`bool` class is a subclass of :class:`int` (see :ref:`typesnumeric`).
|
||||
It cannot be subclassed further. Its only instances are ``False`` and
|
||||
``True`` (see :ref:`bltin-boolean-values`).
|
||||
``True`` (see :ref:`typebool`).
|
||||
|
||||
.. index:: pair: Boolean; type
|
||||
|
||||
|
|
|
@ -802,6 +802,39 @@ number, :class:`float`, or :class:`complex`::
|
|||
hash_value = -2
|
||||
return hash_value
|
||||
|
||||
.. _typebool:
|
||||
|
||||
Boolean Type - :class:`bool`
|
||||
============================
|
||||
|
||||
Booleans represent truth values. The :class:`bool` type has exactly two
|
||||
constant instances: ``True`` and ``False``.
|
||||
|
||||
.. index::
|
||||
single: False
|
||||
single: True
|
||||
pair: Boolean; values
|
||||
|
||||
The built-in function :func:`bool` converts any value to a boolean, if the
|
||||
value can be interpreted as a truth value (see section :ref:`truth` above).
|
||||
|
||||
For logical operations, use the :ref:`boolean operators <boolean>` ``and``,
|
||||
``or`` and ``not``.
|
||||
When applying the bitwise operators ``&``, ``|``, ``^`` to two booleans, they
|
||||
return a bool equivalent to the logical operations "and", "or", "xor". However,
|
||||
the logical operators ``and``, ``or`` and ``!=`` should be preferred
|
||||
over ``&``, ``|`` and ``^``.
|
||||
|
||||
.. deprecated:: 3.12
|
||||
|
||||
The use of the bitwise inversion operator ``~`` is deprecated and will
|
||||
raise an error in Python 3.14.
|
||||
|
||||
:class:`bool` is a subclass of :class:`int` (see :ref:`typesnumeric`). In
|
||||
many numeric contexts, ``False`` and ``True`` behave like the integers 0 and 1, respectively.
|
||||
However, relying on this is discouraged; explicitly convert using :func:`int`
|
||||
instead.
|
||||
|
||||
.. _typeiter:
|
||||
|
||||
Iterator Types
|
||||
|
@ -5394,27 +5427,6 @@ information. There is exactly one ``NotImplemented`` object.
|
|||
It is written as ``NotImplemented``.
|
||||
|
||||
|
||||
.. _bltin-boolean-values:
|
||||
|
||||
Boolean Values
|
||||
--------------
|
||||
|
||||
Boolean values are the two constant objects ``False`` and ``True``. They are
|
||||
used to represent truth values (although other values can also be considered
|
||||
false or true). In numeric contexts (for example when used as the argument to
|
||||
an arithmetic operator), they behave like the integers 0 and 1, respectively.
|
||||
The built-in function :func:`bool` can be used to convert any value to a
|
||||
Boolean, if the value can be interpreted as a truth value (see section
|
||||
:ref:`truth` above).
|
||||
|
||||
.. index::
|
||||
single: False
|
||||
single: True
|
||||
pair: Boolean; values
|
||||
|
||||
They are written as ``False`` and ``True``, respectively.
|
||||
|
||||
|
||||
.. _typesinternal:
|
||||
|
||||
Internal Objects
|
||||
|
|
|
@ -710,6 +710,12 @@ Deprecated
|
|||
replaced by :data:`calendar.Month.JANUARY` and :data:`calendar.Month.FEBRUARY`.
|
||||
(Contributed by Prince Roshan in :gh:`103636`.)
|
||||
|
||||
* The bitwise inversion operator (``~``) on bool is deprecated. It will throw an
|
||||
error in Python 3.14. Use ``not`` for logical negation of bools instead.
|
||||
In the rare case that you really need the bitwise inversion of the underlying
|
||||
``int``, convert to int explicitly with ``~int(x)``. (Contributed by Tim Hoffmann
|
||||
in :gh:`103487`.)
|
||||
|
||||
Pending Removal in Python 3.13
|
||||
------------------------------
|
||||
|
||||
|
|
|
@ -58,8 +58,22 @@ def test_math(self):
|
|||
self.assertEqual(-True, -1)
|
||||
self.assertEqual(abs(True), 1)
|
||||
self.assertIsNot(abs(True), True)
|
||||
self.assertEqual(~False, -1)
|
||||
self.assertEqual(~True, -2)
|
||||
with self.assertWarns(DeprecationWarning):
|
||||
# We need to put the bool in a variable, because the constant
|
||||
# ~False is evaluated at compile time due to constant folding;
|
||||
# consequently the DeprecationWarning would be issued during
|
||||
# module loading and not during test execution.
|
||||
false = False
|
||||
self.assertEqual(~false, -1)
|
||||
with self.assertWarns(DeprecationWarning):
|
||||
# also check that the warning is issued in case of constant
|
||||
# folding at compile time
|
||||
self.assertEqual(eval("~False"), -1)
|
||||
with self.assertWarns(DeprecationWarning):
|
||||
true = True
|
||||
self.assertEqual(~true, -2)
|
||||
with self.assertWarns(DeprecationWarning):
|
||||
self.assertEqual(eval("~True"), -2)
|
||||
|
||||
self.assertEqual(False+2, 2)
|
||||
self.assertEqual(True+2, 3)
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
The bitwise inversion operator (``~``) on bool is deprecated.
|
||||
It returns the bitwise inversion of the underlying ``int`` representation such that
|
||||
``bool(~True) == True``, which can be confusing. Use ``not`` for logical negation
|
||||
of bools. In the rare case that you really need the bitwise inversion of the underlying ``int``,
|
||||
convert to int explicitly ``~int(x)``.
|
|
@ -73,6 +73,22 @@ bool_vectorcall(PyObject *type, PyObject * const*args,
|
|||
|
||||
/* Arithmetic operations redefined to return bool if both args are bool. */
|
||||
|
||||
static PyObject *
|
||||
bool_invert(PyObject *v)
|
||||
{
|
||||
if (PyErr_WarnEx(PyExc_DeprecationWarning,
|
||||
"Bitwise inversion '~' on bool is deprecated. This "
|
||||
"returns the bitwise inversion of the underlying int "
|
||||
"object and is usually not what you expect from negating "
|
||||
"a bool. Use the 'not' operator for boolean negation or "
|
||||
"~int(x) if you really want the bitwise inversion of the "
|
||||
"underlying int.",
|
||||
1) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
return PyLong_Type.tp_as_number->nb_invert(v);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
bool_and(PyObject *a, PyObject *b)
|
||||
{
|
||||
|
@ -119,7 +135,7 @@ static PyNumberMethods bool_as_number = {
|
|||
0, /* nb_positive */
|
||||
0, /* nb_absolute */
|
||||
0, /* nb_bool */
|
||||
0, /* nb_invert */
|
||||
(unaryfunc)bool_invert, /* nb_invert */
|
||||
0, /* nb_lshift */
|
||||
0, /* nb_rshift */
|
||||
bool_and, /* nb_and */
|
||||
|
|
Loading…
Reference in a new issue