PEP 671: Rewrite the implementation section

This commit is contained in:
Chris Angelico 2021-10-30 17:44:32 +11:00
parent 26f8641a15
commit 5c9ce152a1
1 changed files with 24 additions and 19 deletions

View File

@ -146,39 +146,44 @@ Implementation details
The following relates to the reference implementation, and is not necessarily
part of the specification.
An **argument default**, rather than being an arbitrary value, is now a tuple
of 1-2 values. The first value is descriptive text and may be ``None``; the
compiler is free to put the source code for the default here, or None, on any
basis. (The reference implementation omits them from early-bound defaults, and
retains them for late-bound ones.) If there is a second value, it is an early
bound default value and will be used as the function parameter when none is
given.
Argument defaults (positional or keyword) have both their values, as already
retained, and an extra piece of information. For positional arguments, the
extras are stored in a tuple in ``__defaults_extra__``, and for keyword-only,
a dict in ``__kwdefaults_extra__``. If this attribute is ``None``, it is
equivalent to having ``None`` for every argument default.
When there is no second value in the tuple, and the parameter is omitted, the
For each parameter with a late-bound default, the special value ``Ellipsis``
is stored as the value placeholder, and the corresponding extra information
needs to be queried. If it is ``None``, then the default is indeed the value
``Ellipsis``; otherwise, it is a descriptive string and the true value is
calculated as the function begins.
When a parameter with a late-bound default is omitted, the
function will begin with the parameter unbound. The function begins by testing
for each parameter with a late-bound default, and if unbound, evaluates the
original expression.
Inspecting the function (eg ``help()``) will use the provided description
where available, falling back on the repr of the value, or if there is none,
report "=> <calculated>".
Costs
-----
Every function default argument must now be wrapped in a tuple. This adds 56
bytes (CPython 3.11, 64-bit Linux), but where the same value is used in many
places (eg ``None``), this tuple can be shared.
When no late-bound argument defaults are used, the following costs should be
all that are incurred:
Mapping arguments to parameters incurs the cost of tuple unpacking.
* Function objects require two additional pointers, which will be NULL
* Compiling code and constructing functions have additional flag checks
* Using ``Ellipsis`` as a default value will require run-time verification
to see if late-bound defaults exist.
Constructing functions manually using FunctionType requires additional checks.
These costs are expected to be minimal (on 64-bit Linux, this increases all
function objects from 152 bytes to 168), with virtually no run-time cost when
late-bound defaults are not used.
Backward incompatibility
------------------------
Inspecting ``spam.__defaults__`` shows a tuple of tuples rather than a tuple
of values. Similarly, ``spam.__kwdefaults__`` is a dict of tuples.
Where late-bound defaults are not used, behaviour should be identical. Care
should be taken if Ellipsis is found, as it may not represent itself, but
beyond that, tools should see existing code unchanged.
References
==========