gh-109218: Improve documentation for the complex() constructor (GH-119687)

* Remove the equivalence with real+imag*1j which can be incorrect in corner
  cases (non-finite numbers, the sign of zeroes).
* Separately document the three roles of the constructor: parsing a string,
  converting a number, and constructing a complex from components.
* Document positional-only parameters of complex(), float(), int() and bool()
  as positional-only.
* Add examples for complex() and int().
* Specify the grammar of the string for complex().
* Improve the grammar of the string for float().
* Describe more explicitly the behavior when real and/or imag arguments are
  complex numbers. (This will be deprecated in future.)
This commit is contained in:
Serhiy Storchaka 2024-05-30 23:20:07 +03:00 committed by GitHub
parent 1c04c63ced
commit ec1ba26460
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 135 additions and 63 deletions

View File

@ -43,10 +43,7 @@ Conversions to and from polar coordinates
A Python complex number ``z`` is stored internally using *rectangular* A Python complex number ``z`` is stored internally using *rectangular*
or *Cartesian* coordinates. It is completely determined by its *real or *Cartesian* coordinates. It is completely determined by its *real
part* ``z.real`` and its *imaginary part* ``z.imag``. In other part* ``z.real`` and its *imaginary part* ``z.imag``.
words::
z == z.real + z.imag*1j
*Polar coordinates* give an alternative way to represent a complex *Polar coordinates* give an alternative way to represent a complex
number. In polar coordinates, a complex number *z* is defined by the number. In polar coordinates, a complex number *z* is defined by the
@ -90,7 +87,7 @@ rectangular coordinates to polar coordinates and back.
.. function:: rect(r, phi) .. function:: rect(r, phi)
Return the complex number *x* with polar coordinates *r* and *phi*. Return the complex number *x* with polar coordinates *r* and *phi*.
Equivalent to ``r * (math.cos(phi) + math.sin(phi)*1j)``. Equivalent to ``complex(r * math.cos(phi), r * math.sin(phi))``.
Power and logarithmic functions Power and logarithmic functions

View File

@ -141,10 +141,11 @@ are always available. They are listed here in alphabetical order.
See also :func:`format` for more information. See also :func:`format` for more information.
.. class:: bool(x=False) .. class:: bool(object=False, /)
Return a Boolean value, i.e. one of ``True`` or ``False``. *x* is converted Return a Boolean value, i.e. one of ``True`` or ``False``. The argument
using the standard :ref:`truth testing procedure <truth>`. If *x* is false is converted using the standard :ref:`truth testing procedure <truth>`.
If the argument is false
or omitted, this returns ``False``; otherwise, it returns ``True``. The or omitted, this returns ``False``; otherwise, it returns ``True``. The
:class:`bool` class is a subclass of :class:`int` (see :ref:`typesnumeric`). :class:`bool` class is a subclass of :class:`int` (see :ref:`typesnumeric`).
It cannot be subclassed further. Its only instances are ``False`` and It cannot be subclassed further. Its only instances are ``False`` and
@ -153,7 +154,7 @@ are always available. They are listed here in alphabetical order.
.. index:: pair: Boolean; type .. index:: pair: Boolean; type
.. versionchanged:: 3.7 .. versionchanged:: 3.7
*x* is now a positional-only parameter. The parameter is now positional-only.
.. function:: breakpoint(*args, **kws) .. function:: breakpoint(*args, **kws)
@ -371,29 +372,73 @@ are always available. They are listed here in alphabetical order.
support for top-level ``await``, ``async for``, and ``async with``. support for top-level ``await``, ``async for``, and ``async with``.
.. class:: complex(real=0, imag=0) .. class:: complex(number=0, /)
complex(string) complex(string, /)
complex(real=0, imag=0)
Return a complex number with the value *real* + *imag*\*1j or convert a string Convert a single string or number to a complex number, or create a
or number to a complex number. If the first parameter is a string, it will complex number from real and imaginary parts.
be interpreted as a complex number and the function must be called without a
second parameter. The second parameter can never be a string. Each argument
may be any numeric type (including complex). If *imag* is omitted, it
defaults to zero and the constructor serves as a numeric conversion like
:class:`int` and :class:`float`. If both arguments are omitted, returns
``0j``.
Examples:
.. doctest::
>>> complex('+1.23')
(1.23+0j)
>>> complex('-4.5j')
-4.5j
>>> complex('-1.23+4.5j')
(-1.23+4.5j)
>>> complex('\t( -1.23+4.5J )\n')
(-1.23+4.5j)
>>> complex('-Infinity+NaNj')
(-inf+nanj)
>>> complex(1.23)
(1.23+0j)
>>> complex(imag=-4.5)
-4.5j
>>> complex(-1.23, 4.5)
(-1.23+4.5j)
If the argument is a string, it must contain either a real part (in the
same format as for :func:`float`) or an imaginary part (in the same
format but with a ``'j'`` or ``'J'`` suffix), or both real and imaginary
parts (the sign of the imaginary part is mandatory in this case).
The string can optionally be surrounded by whitespaces and the round
parentheses ``'('`` and ``')'``, which are ignored.
The string must not contain whitespace between ``'+'``, ``'-'``, the
``'j'`` or ``'J'`` suffix, and the decimal number.
For example, ``complex('1+2j')`` is fine, but ``complex('1 + 2j')`` raises
:exc:`ValueError`.
More precisely, the input must conform to the :token:`~float:complexvalue`
production rule in the following grammar, after parentheses and leading and
trailing whitespace characters are removed:
.. productionlist:: float
complexvalue: `floatvalue` |
: `floatvalue` ("j" | "J") |
: `floatvalue` `sign` `absfloatvalue` ("j" | "J")
If the argument is a number, the constructor serves as a numeric
conversion like :class:`int` and :class:`float`.
For a general Python object ``x``, ``complex(x)`` delegates to For a general Python object ``x``, ``complex(x)`` delegates to
``x.__complex__()``. If :meth:`~object.__complex__` is not defined then it falls back ``x.__complex__()``.
to :meth:`~object.__float__`. If :meth:`!__float__` is not defined then it falls back If :meth:`~object.__complex__` is not defined then it falls back
to :meth:`~object.__float__`.
If :meth:`!__float__` is not defined then it falls back
to :meth:`~object.__index__`. to :meth:`~object.__index__`.
.. note:: If two arguments are provided or keyword arguments are used, each argument
may be any numeric type (including complex).
If both arguments are real numbers, return a complex number with the real
component *real* and the imaginary component *imag*.
If both arguments are complex numbers, return a complex number with the real
component ``real.real-imag.imag`` and the imaginary component
``real.imag+imag.real``.
If one of arguments is a real number, only its real component is used in
the above expressions.
When converting from a string, the string must not contain whitespace If all arguments are omitted, returns ``0j``.
around the central ``+`` or ``-`` operator. For example,
``complex('1+2j')`` is fine, but ``complex('1 + 2j')`` raises
:exc:`ValueError`.
The complex type is described in :ref:`typesnumeric`. The complex type is described in :ref:`typesnumeric`.
@ -682,21 +727,38 @@ are always available. They are listed here in alphabetical order.
elements of *iterable* for which *function* is false. elements of *iterable* for which *function* is false.
.. class:: float(x=0.0) .. class:: float(number=0.0, /)
float(string, /)
.. index:: .. index::
single: NaN single: NaN
single: Infinity single: Infinity
Return a floating point number constructed from a number or string *x*. Return a floating point number constructed from a number or a string.
Examples:
.. doctest::
>>> float('+1.23')
1.23
>>> float(' -12345\n')
-12345.0
>>> float('1e-003')
0.001
>>> float('+1E6')
1000000.0
>>> float('-Infinity')
-inf
If the argument is a string, it should contain a decimal number, optionally If the argument is a string, it should contain a decimal number, optionally
preceded by a sign, and optionally embedded in whitespace. The optional preceded by a sign, and optionally embedded in whitespace. The optional
sign may be ``'+'`` or ``'-'``; a ``'+'`` sign has no effect on the value sign may be ``'+'`` or ``'-'``; a ``'+'`` sign has no effect on the value
produced. The argument may also be a string representing a NaN produced. The argument may also be a string representing a NaN
(not-a-number), or positive or negative infinity. More precisely, the (not-a-number), or positive or negative infinity.
input must conform to the ``floatvalue`` production rule in the following More precisely, the input must conform to the :token:`~float:floatvalue`
grammar, after leading and trailing whitespace characters are removed: production rule in the following grammar, after leading and trailing
whitespace characters are removed:
.. productionlist:: float .. productionlist:: float
sign: "+" | "-" sign: "+" | "-"
@ -705,9 +767,10 @@ are always available. They are listed here in alphabetical order.
digit: <a Unicode decimal digit, i.e. characters in Unicode general category Nd> digit: <a Unicode decimal digit, i.e. characters in Unicode general category Nd>
digitpart: `digit` (["_"] `digit`)* digitpart: `digit` (["_"] `digit`)*
number: [`digitpart`] "." `digitpart` | `digitpart` ["."] number: [`digitpart`] "." `digitpart` | `digitpart` ["."]
exponent: ("e" | "E") ["+" | "-"] `digitpart` exponent: ("e" | "E") [`sign`] `digitpart`
floatnumber: number [`exponent`] floatnumber: `number` [`exponent`]
floatvalue: [`sign`] (`floatnumber` | `infinity` | `nan`) absfloatvalue: `floatnumber` | `infinity` | `nan`
floatvalue: [`sign`] `absfloatvalue`
Case is not significant, so, for example, "inf", "Inf", "INFINITY", and Case is not significant, so, for example, "inf", "Inf", "INFINITY", and
"iNfINity" are all acceptable spellings for positive infinity. "iNfINity" are all acceptable spellings for positive infinity.
@ -723,26 +786,13 @@ are always available. They are listed here in alphabetical order.
If no argument is given, ``0.0`` is returned. If no argument is given, ``0.0`` is returned.
Examples::
>>> float('+1.23')
1.23
>>> float(' -12345\n')
-12345.0
>>> float('1e-003')
0.001
>>> float('+1E6')
1000000.0
>>> float('-Infinity')
-inf
The float type is described in :ref:`typesnumeric`. The float type is described in :ref:`typesnumeric`.
.. versionchanged:: 3.6 .. versionchanged:: 3.6
Grouping digits with underscores as in code literals is allowed. Grouping digits with underscores as in code literals is allowed.
.. versionchanged:: 3.7 .. versionchanged:: 3.7
*x* is now a positional-only parameter. The parameter is now positional-only.
.. versionchanged:: 3.8 .. versionchanged:: 3.8
Falls back to :meth:`~object.__index__` if :meth:`~object.__float__` is not defined. Falls back to :meth:`~object.__index__` if :meth:`~object.__float__` is not defined.
@ -926,17 +976,36 @@ are always available. They are listed here in alphabetical order.
with the result after successfully reading input. with the result after successfully reading input.
.. class:: int(x=0) .. class:: int(number=0, /)
int(x, base=10) int(string, /, base=10)
Return an integer object constructed from a number or string *x*, or return Return an integer object constructed from a number or a string, or return
``0`` if no arguments are given. If *x* defines :meth:`~object.__int__`, ``0`` if no arguments are given.
``int(x)`` returns ``x.__int__()``. If *x* defines :meth:`~object.__index__`,
it returns ``x.__index__()``. If *x* defines :meth:`~object.__trunc__`, Examples:
.. doctest::
>>> int(123.45)
123
>>> int('123')
123
>>> int(' -12_345\n')
-12345
>>> int('FACE', 16)
64206
>>> int('0xface', 0)
64206
>>> int('01110011', base=2)
115
If the argument defines :meth:`~object.__int__`,
``int(x)`` returns ``x.__int__()``. If the argument defines :meth:`~object.__index__`,
it returns ``x.__index__()``. If the argument defines :meth:`~object.__trunc__`,
it returns ``x.__trunc__()``. it returns ``x.__trunc__()``.
For floating point numbers, this truncates towards zero. For floating point numbers, this truncates towards zero.
If *x* is not a number or if *base* is given, then *x* must be a string, If the argument is not a number or if *base* is given, then it must be a string,
:class:`bytes`, or :class:`bytearray` instance representing an integer :class:`bytes`, or :class:`bytearray` instance representing an integer
in radix *base*. Optionally, the string can be preceded by ``+`` or ``-`` in radix *base*. Optionally, the string can be preceded by ``+`` or ``-``
(with no space in between), have leading zeros, be surrounded by whitespace, (with no space in between), have leading zeros, be surrounded by whitespace,
@ -966,7 +1035,7 @@ are always available. They are listed here in alphabetical order.
Grouping digits with underscores as in code literals is allowed. Grouping digits with underscores as in code literals is allowed.
.. versionchanged:: 3.7 .. versionchanged:: 3.7
*x* is now a positional-only parameter. The first parameter is now positional-only.
.. versionchanged:: 3.8 .. versionchanged:: 3.8
Falls back to :meth:`~object.__index__` if :meth:`~object.__int__` is not defined. Falls back to :meth:`~object.__index__` if :meth:`~object.__int__` is not defined.
@ -977,7 +1046,7 @@ are always available. They are listed here in alphabetical order.
.. versionchanged:: 3.11 .. versionchanged:: 3.11
:class:`int` string inputs and string representations can be limited to :class:`int` string inputs and string representations can be limited to
help avoid denial of service attacks. A :exc:`ValueError` is raised when help avoid denial of service attacks. A :exc:`ValueError` is raised when
the limit is exceeded while converting a string *x* to an :class:`int` or the limit is exceeded while converting a string to an :class:`int` or
when converting an :class:`int` into a string would exceed the limit. when converting an :class:`int` into a string would exceed the limit.
See the :ref:`integer string conversion length limitation See the :ref:`integer string conversion length limitation
<int_max_str_digits>` documentation. <int_max_str_digits>` documentation.

View File

@ -94,9 +94,12 @@ PyDoc_STRVAR(complex_new__doc__,
"complex(real=0, imag=0)\n" "complex(real=0, imag=0)\n"
"--\n" "--\n"
"\n" "\n"
"Create a complex number from a real part and an optional imaginary part.\n" "Create a complex number from a string or numbers.\n"
"\n" "\n"
"This is equivalent to (real + imag*1j) where imag defaults to 0."); "If a string is given, parse it as a complex number.\n"
"If a single number is given, convert it to a complex number.\n"
"If the \'real\' or \'imag\' arguments are given, create a complex number\n"
"with the specified real and imaginary components.");
static PyObject * static PyObject *
complex_new_impl(PyTypeObject *type, PyObject *r, PyObject *i); complex_new_impl(PyTypeObject *type, PyObject *r, PyObject *i);
@ -157,4 +160,4 @@ skip_optional_pos:
exit: exit:
return return_value; return return_value;
} }
/*[clinic end generated code: output=04e6261649967b30 input=a9049054013a1b77]*/ /*[clinic end generated code: output=295ecfd71389d7fe input=a9049054013a1b77]*/

View File

@ -911,14 +911,17 @@ complex.__new__ as complex_new
real as r: object(c_default="NULL") = 0 real as r: object(c_default="NULL") = 0
imag as i: object(c_default="NULL") = 0 imag as i: object(c_default="NULL") = 0
Create a complex number from a real part and an optional imaginary part. Create a complex number from a string or numbers.
This is equivalent to (real + imag*1j) where imag defaults to 0. If a string is given, parse it as a complex number.
If a single number is given, convert it to a complex number.
If the 'real' or 'imag' arguments are given, create a complex number
with the specified real and imaginary components.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
complex_new_impl(PyTypeObject *type, PyObject *r, PyObject *i) complex_new_impl(PyTypeObject *type, PyObject *r, PyObject *i)
/*[clinic end generated code: output=b6c7dd577b537dc1 input=f4c667f2596d4fd1]*/ /*[clinic end generated code: output=b6c7dd577b537dc1 input=ff4268dc540958a4]*/
{ {
PyObject *tmp; PyObject *tmp;
PyNumberMethods *nbr, *nbi = NULL; PyNumberMethods *nbr, *nbi = NULL;