From 1f0351ab6ef8e734f990620bd224c2b857b8e623 Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Wed, 12 Apr 2023 21:49:30 +0200 Subject: [PATCH 1/5] gh-82012: Deprecate bitwise inversion (~) of bool 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 --- Doc/whatsnew/3.12.rst | 6 ++++++ Lib/test/test_bool.py | 18 ++++++++++++++++-- ...23-04-12-19-55-24.gh-issue-82012.FlcJAh.rst | 5 +++++ Objects/boolobject.c | 18 +++++++++++++++++- 4 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-04-12-19-55-24.gh-issue-82012.FlcJAh.rst diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index f4ee30b0d4d9eb..a342140b03b74f 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -705,6 +705,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 ------------------------------ diff --git a/Lib/test/test_bool.py b/Lib/test/test_bool.py index 916e22a527a8e0..34ecb45f161dfe 100644 --- a/Lib/test/test_bool.py +++ b/Lib/test/test_bool.py @@ -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) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-12-19-55-24.gh-issue-82012.FlcJAh.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-12-19-55-24.gh-issue-82012.FlcJAh.rst new file mode 100644 index 00000000000000..819a2359bf6fae --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-12-19-55-24.gh-issue-82012.FlcJAh.rst @@ -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)``. diff --git a/Objects/boolobject.c b/Objects/boolobject.c index 597a76fa5cb162..0300f7bb4e3dc0 100644 --- a/Objects/boolobject.c +++ b/Objects/boolobject.c @@ -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 */ From 3632ba5d40540462c1e5e287d7e36796f85f65f9 Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Sun, 30 Apr 2023 23:39:02 +0200 Subject: [PATCH 2/5] Document bool behavior for bitwise operations This also pulls the bool type to top-level of the type description page. Before it was only documented in the section "Other Built-in Types / Boolean Values". --- Doc/library/stdtypes.rst | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 2360472b31f175..b66ba739113268 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -802,6 +802,31 @@ 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``. + +Other types can be cast to bool explicitly using the function :func:`bool`. +Additionally, they are implicitly interpreted as bool in some contexts - see +:ref:`truth`. + +For logical operations, use the :ref:`boolean operators ` ``and``, +``or`` and ``not``. +When applying the bitwise operators ``&``, ``|``, ``^`` to two booleans, they +return a bool equivalent to the logical operations "and", "or", "xor". Still, +for ``&`` and ``|``, the logical operators ``and`` and ``or`` are preferred. +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, bools behave like the integers 0 and 1, respectively. +However, relying on this is discouraged; explicitly convert using :func:`int` +instead. + .. _typeiter: Iterator Types @@ -5399,21 +5424,14 @@ It is written as ``NotImplemented``. 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). +Boolean values are the two constant objects ``False`` and ``True``. See +:ref:`typebool` for more info. .. index:: single: False single: True pair: Boolean; values -They are written as ``False`` and ``True``, respectively. - .. _typesinternal: From 2cbfe2da9c7a7c778ca18e01b0ac9225c119eca7 Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Mon, 1 May 2023 02:43:57 +0200 Subject: [PATCH 3/5] Move section "Boolean Values" into "Boolean Type" --- Doc/library/functions.rst | 2 +- Doc/library/stdtypes.rst | 33 +++++++++++++-------------------- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index a5e86ef0f9eb59..085a11c3caa708 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -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 diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index b66ba739113268..5c70ba27f90ad4 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -808,19 +808,26 @@ Boolean Type - :class:`bool` ============================ Booleans represent truth values. The :class:`bool` type has exactly two -constant instances ``True`` and ``False``. +constant instances: ``True`` and ``False``. -Other types can be cast to bool explicitly using the function :func:`bool`. -Additionally, they are implicitly interpreted as bool in some contexts - see -:ref:`truth`. +.. 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 ` ``and``, ``or`` and ``not``. When applying the bitwise operators ``&``, ``|``, ``^`` to two booleans, they return a bool equivalent to the logical operations "and", "or", "xor". Still, for ``&`` and ``|``, the logical operators ``and`` and ``or`` are preferred. -The use of the bitwise inversion operator ``~`` is deprecated and will raise -an error in Python 3.14. + +.. 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, bools behave like the integers 0 and 1, respectively. @@ -5419,20 +5426,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``. See -:ref:`typebool` for more info. - -.. index:: - single: False - single: True - pair: Boolean; values - - .. _typesinternal: Internal Objects From e5ec711a01b427410b5010058d59ebd7a3ad7dfe Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Mon, 1 May 2023 08:21:27 +0200 Subject: [PATCH 4/5] Update Doc/library/stdtypes.rst Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com> --- Doc/library/stdtypes.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 5c70ba27f90ad4..4b4d56aadc1636 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -821,8 +821,9 @@ value can be interpreted as a truth value (see section :ref:`truth` above). For logical operations, use the :ref:`boolean operators ` ``and``, ``or`` and ``not``. When applying the bitwise operators ``&``, ``|``, ``^`` to two booleans, they -return a bool equivalent to the logical operations "and", "or", "xor". Still, -for ``&`` and ``|``, the logical operators ``and`` and ``or`` are preferred. +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 From 2db5864da0f0207d0bb475222493aeed4bded8be Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Mon, 1 May 2023 08:21:48 +0200 Subject: [PATCH 5/5] Update Doc/library/stdtypes.rst Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com> --- Doc/library/stdtypes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 4b4d56aadc1636..f6662b4336c276 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -831,7 +831,7 @@ over ``&``, ``|`` and ``^``. raise an error in Python 3.14. :class:`bool` is a subclass of :class:`int` (see :ref:`typesnumeric`). In -many numeric contexts, bools behave like the integers 0 and 1, respectively. +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. pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy