PEP 570: Edit Sections and How to Teach (GH-975)

* Correct grammar and style.
* Update the "How to teach" section.
* Expand grammar specification.

Signed-off-by: Carol Willing <carolcode@willingconsulting.com>
This commit is contained in:
Carol Willing 2019-04-05 12:25:17 -07:00 committed by Pablo Galindo
parent 4b703079ff
commit 1e2f409b47
1 changed files with 238 additions and 108 deletions

View File

@ -19,27 +19,34 @@ Abstract
========
This PEP proposes to introduce a new syntax, ``/``, for specifying
positional-only parameters in Python.
positional-only parameters in Python function definitions.
Positional-only parameters have no externally-usable name. When a function
accepting positional-only parameters is called, positional arguments are mapped
to these parameters based solely on their position.
to these parameters based solely on their order.
Design of APIs (application programmable interfaces) is important for library
authors to ensure correct and intended usage of an API. The inability to
specify which parameters are positional-only requires careful consideration
when choosing appropriate parameter names, even if the parameters are required
or have no external semantic meaning for callers of the API.
When designing APIs (application programmable interfaces), library
authors try to ensure correct and intended usage of an API. Without the ability to
specify which parameters are positional-only, library authors must use careful consideration
when choosing appropriate parameter names. This consideration must be taken
into account even if the function requires the parameters or the parameters
have no external semantic meaning for callers of the API.
In this PEP, we discuss Python's history and current semantics for
positional-only parameters, the problems encountered by not having them, how
these problems are handled without language-intrinsic support, and the benefits
of having positional-only parameters. With context of the motivation, we then
discuss the rationale for why this change should be a feature intrinsic to the
language. Next, we propose the syntax for demarcating positional-only
parameters. Following, we present how to teach this new feature. Finally, we
conclude with noting rejected ideas in further detail, complementing the
rationale.
In this PEP, we discuss:
* Python's history and current semantics for positional-only parameters
* the problems encountered by not having them
* how these problems are handled without language-intrinsic support for
positional-only parameters
* the benefits of having positional-only parameters
Within context of the motivation, we then:
* discuss why positional-only parameters should be a feature intrinsic to the
language
* propose the syntax for demarcating positional-only parameters
* present how to teach this new feature
* note rejected ideas in further detail
==========
Motivation
@ -50,30 +57,31 @@ History of Positional-Only Parameter Semantics in Python
--------------------------------------------------------
Python originally supported positional-only parameters. Early versions of the
language lacked the ability to call functions binding arguments to a parameter
language lacked the ability to call functions with arguments bound to parameters
by name. Around Python 1.0, parameter semantics changed to be
positional-or-keyword. Since then, callers have been able to provide arguments
to a function either positionally or by the keyword name specified in the
function's definition.
In current versions of Python, many CPython "builtin" and standard library
functions only accept positional-only arguments. The resulting semantics can be
functions only accept positional-only parameters. The resulting semantics can be
easily observed by calling one of these functions using keyword arguments::
>>> help(pow)
...
pow(x, y, z=None, /)
...
>>> pow(x=5, y=3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: pow() takes no keyword arguments
``pow()`` clearly expresses that its arguments are positional-only via the
``pow()`` expresses that its parameters are positional-only via the
``/`` marker. However, this is only a documentation convention; Python
developers cannot use this syntax in code.
There are other functions with other interesting semantics:
There are functions with other interesting semantics:
* ``range()``, an overloaded function, accepts an optional parameter to the
*left* of its required parameter. [#RANGE]_
@ -83,10 +91,10 @@ There are other functions with other interesting semantics:
would occlude that name going into the ``**kwarg`` keyword variadic parameter
dict. [#DICT]_
One can emulate the aforementioned semantics in Python code by accepting
One can emulate these semantics in Python code by accepting
``(*args, **kwargs)`` and parsing the arguments manually. However, this results
in a disconnect between the function definition and what the function
contractually accepts — the function definition does not match the logic of the
contractually accepts. The function definition does not match the logic of the
argument handling.
Additionally, the ``/`` syntax is used beyond CPython for specifying similar
@ -107,39 +115,39 @@ Challenges for Library Authors
With positional-or-keyword parameters, the mix of calling conventions is not
always desirable. Authors may want to restrict usage of an API by disallowing
calling them with keyword arguments, which exposes the name of the parameter as
part of the public API. This is especially useful for required parameters that
already have semantic meaning with respect to function (e.g,
calling the API with keyword arguments, which exposes the name of the parameter when
part of the public API. This approach is especially useful for required function
parameters that already have semantic meaning (e.g,
``namedtuple(typenames, field_names, …)`` or when the parameter name has no
true external meaning (e.g., ``arg1``, ``arg2``, …, etc for ``min()``). If a
caller of an API starts using a keyword argument, the parameter cannot be
renamed because it would be a breaking change.
caller of an API starts using a keyword argument, the library author cannot rename
the parameter because it would be a breaking change.
Positional-only parameters can be emulated by extracting arguments from
``*args`` one by one. However, this approach is error-prone and is not
synonymous with the function definition, as previously mentioned. The usage of
the function is ambiguous and forces callers to look at ``help()`` or the
associated auto-generated documentation to understand what parameters the
function contractually accepts.
the function is ambiguous and forces callers to look at ``help()``, the
associated auto-generated documentation, or source code to understand what
parameters the function contractually accepts.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Challenges for Callers of an API
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Callers may be surprised when first encountering this notation. This is
expected given that it has only recently been documented
Callers may be surprised when first encountering positional-only notation. This
is expected given that it has only recently been documented
[#document-positional-only]_ and it is not possible to use in Python code. For
these reasons, this notation is currently an outlier that appears only in
CPython's APIs developed in C. Documenting the notation and making it possible
to be used in Python code would eliminate this disconnect.
Furthermore, the documentation for positional-only parameters is inconsistent:
Furthermore, the current documentation for positional-only parameters is inconsistent:
* Some functions denote optional groups of positional-only arguments by
* Some functions denote optional groups of positional-only parameters by
enclosing them in nested square brackets. [#BORDER]_
* Some functions denote optional groups of positional-only arguments by
presenting multiple prototypes with varying numbers of arguments.
* Some functions denote optional groups of positional-only parameters by
presenting multiple prototypes with varying numbers of parameters.
[#SENDFILE]_
* Some functions use *both* of the above approaches. [#RANGE]_ [#ADDCH]_
@ -147,35 +155,41 @@ Furthermore, the documentation for positional-only parameters is inconsistent:
Another point of consideration the current documentation does not distinguish
whether a function takes positional-only parameters. ``open()`` accepts keyword
arguments; however, ``ord()`` does not — there is no way of telling just by
reading the documentation.
reading the existing documentation.
--------------------------------------
Benefits of Positional-Only Parameters
--------------------------------------
Positional-only parameters gives more control to library authors to better
Positional-only parameters give more control to library authors to better
express the intended usage of an API and allows the API to evolve in a safe,
backward-compatible way. Additionally, it makes the Python language more
consistent with respect to existing documentation and the behavior of various
consistent with existing documentation and the behavior of various
"builtin" and standard library functions.
^^^^^^^^^^^^^^^^^^^^^^^^^^
Empowering Library Authors
^^^^^^^^^^^^^^^^^^^^^^^^^^
Library authors would have have the flexibility to change the name of
positional-only parameters without breaking callers. It reduces the
Library authors would have the flexibility to change the name of
positional-only parameters without breaking callers. This flexibility reduces the
cognitive burden for choosing an appropriate public-facing name for required
parameters or parameters that have no true external semantic meaning.
Positional-only parameters are useful in several situations. An extreme
Positional-only parameters are useful in several situations such as:
* when a function accepts any keyword argument but also can accept a positional one
* when a parameter has no external semantic meaning
* when an API's parameters are required and unambiguous
A key
scenario is when a function accepts any keyword argument but can also accepts a
positional one. Prominent examples are ``Formatter.format`` and
``dict.update``. For instance, ``dict.update`` accepts a dictionary
(positionally), an iterable of key/value pairs (positionally), or multiple
keyword arguments. In this scenario, if the dictionary parameter were not
positional-only, the user could not use the name that the function definition
uses for said parameter or, conversely, the function could not distinguish
uses for the parameter or, conversely, the function could not distinguish
easily if the argument received is the dictionary/iterable or a keyword
argument for updating the key/value pair.
@ -190,13 +204,13 @@ The name of the parameter provides no intrinsic value and forces the API author
to maintain its name forever since callers might pass ``x`` as a keyword
argument.
Additionally, positional-only arguments are useful when an API's parameters
Additionally, positional-only parameters are useful when an API's parameters
are required and is unambiguous with respect to function. For example::
def add_to_queue(item: QueueItem):
...
It is clear by the name of the function the argument expected. A keyword
The name of the function makes clear the argument expected. A keyword
argument provides minimal benefit and also limits the future evolution of the
API. Say at a later time we want this function to be able to take multiple
items, while preserving backwards compatibility::
@ -210,9 +224,9 @@ or to take them by using argument lists::
...
the author would be forced to always keep the original parameter name to avoid
potentially break callers.
potentially breaking callers.
By being able to specify positional-only arguments, an author can change the
By being able to specify positional-only parameters, an author can change the
name of the parameters freely or even change them to ``*args``, as seen in the
previous example. There are multiple function definitions in the standard
library which fall into this category. For example, the required parameter to
@ -224,7 +238,7 @@ keyword to the name ``self`` when calling the method from the class::
io.FileIO.write(self=f, b=b"data")
Indeed, function definitions from the standard library implemented in C usually
take ``self`` as a positional-only argument::
take ``self`` as a positional-only parameter::
>>> help(io.FileIO.write)
Help on method_descriptor:
@ -239,14 +253,15 @@ Improving Language Consistency
The Python language, itself, would be more consistent with positional-only
parameters. If the concept is a normal feature of Python rather than a feature
exclusive to extension modules, it would reduce confusion for users
encountering functions with positional-only arguments. Again, major
encountering functions with positional-only parameters. Some major
third-party packages are already using the ``/`` notation in their function
definitions [#numpy-ufuncs]_ [#scipy-gammaln]_.
Additionally, this would bridge the gap found between "builtin" functions which
Bridging the gap found between "builtin" functions which
specify positional-only parameters and pure Python implementations that lack
the syntax for it. The ``/`` syntax is already exposed in the documentation of
some builtins and interfaces generated by the argument clinic.
the positional syntax would improve consistency. The ``/`` syntax is already exposed
in the existing documentation such as when builtins and interfaces are generated
by the argument clinic.
Another essential aspect to consider is PEP 399 [#PEP399]_, which mandates that
pure Python versions of modules in the standard library *must* have the same
@ -263,14 +278,18 @@ We propose to introduce positional-only parameters as a new syntax to the
Python language.
The new syntax would enable library authors to further control how their API
can be called. It would restrict arguments to be called as positional-only,
while not allowing them to be called as keyword arguments.
can be called. It would designate which parameters must be called as
positional-only, while preventing them from being called as keyword arguments.
Previously, PEP 457 proposed to define the syntax, but with a much broader
scope. This PEP takes the original proposal a step further that by justifying
scope. This PEP takes the original proposal a step further by justifying
the syntax and providing an implementation for the ``/`` syntax in function
definitions.
-----------
Performance
-----------
In addition to the aforementioned benefits, the parsing and handling of
positional-only arguments is faster. This performance benefit can be
demonstrated in this thread about converting keyword arguments to positional:
@ -279,6 +298,10 @@ trend towards moving builtins away from keyword arguments: recently,
backwards-incompatible changes were made to disallow keyword arguments to
``bool``, ``float``, ``list``, ``int``, ``tuple``.
---------------
Maintainability
---------------
Providing a way to specify positional-only parameters in Python would make it
easier to maintain pure Python implementations of C modules. Additionally,
library authors defining functions would have the choice for choosing
@ -302,6 +325,10 @@ This is a well discussed, recurring topic on the Python mailing lists:
* May 2006: `Benji York: [Python-Dev] Positional-only Arguments
<https://mail.python.org/pipermail/python-dev/2006-May/064790.html>`_
----------------
Logical ordering
----------------
Positional-only parameters also have the (minor) benefit of enforcing some
logical order when calling interfaces that make use of them. For example, the
``range`` function takes all its parameters positionally and disallows forms
@ -317,18 +344,22 @@ intended order::
range(start=0, stop=5, step=2)
Another critical aspect which motivates positional-only parameters is PEP 399
-------------------------------------------
Compatibility for Pure Python and C modules
-------------------------------------------
Another critical motivation for positional-only parameters is PEP 399
[#PEP399]_: Pure Python/C Accelerator Module Compatibility Requirements. This
PEP states that :
PEP states that:
This PEP requires that in these instances that the C code must pass the
test suite used for the pure Python code to act as much as a drop-in
replacement as reasonably possible
It is clear that if the C code is implemented using the existing capabilities
If the C code is implemented using the existing capabilities
to implement positional-only parameters using the argument clinic, and related
machinery, it is not possible for the pure Python counterpart to match the
provided interface and requirements. This also creates a disparity between the
provided interface and requirements. This creates a disparity between the
interfaces of some functions and classes in the CPython standard library and
other Python implementations. For example::
@ -345,8 +376,12 @@ goes against the spirit of PEP 399 [#PEP399]_ to avoid duplication of effort by
mandating that all modules added to Python's standard library **must** have a
pure Python implementation with the same interface and semantics.
-------------------------
Consistency in Subclasses
-------------------------
Another scenario where positional-only parameters provide benefit occurs when a
subclass overrides a method of the base class and changes the name of arguments
subclass overrides a method of the base class and changes the name of parameters
that are intended to be positional::
class Base:
@ -376,9 +411,13 @@ hasn't been written yet and over which the author has no control. Having
measures that can facilitate the evolution of interfaces in a
backwards-compatible would be useful for library authors.
-------------
Optimizations
-------------
A final argument in favor of positional-only parameters is that they allow some
new optimizations like the ones already present in the argument clinic due to
the fact that parameters must be passed in strict order. For example, CPython's
the fact that parameters are expected to be passed in strict order. For example, CPython's
internal *METH_FASTCALL* calling convention has been recently specialized for
functions with positional-only parameters to eliminate the cost for handling
empty keywords. Similar performance improvements can be applied when creating
@ -403,15 +442,20 @@ like::
def name(positional_only_parameters, /, positional_or_keyword_parameters,
*, keyword_only_parameters):
All parameters left of the ``/`` are demarcated as positional-only. If ``/``
is not specified in the function definition, that function does not accept any
positional-only arguments. The logic around optional values for
positional-only arguments remains the same as for positional-or-keyword
arguments. Once a positional-only parameter is specified with a default, the
following positional-only and positional-or-keyword arguments need to have
defaults as well. Positional-only parameters which do not have a default
values are *required* positional-only parameters. Therefore the following are
valid signatures::
The following would apply:
* All parameters left of the ``/`` are demarcated as positional-only.
* If ``/`` is not specified in the function definition, that function does not
accept any positional-only arguments.
* The logic around optional values for positional-only parameters remains the
same as for positional-or-keyword parameters.
* Once a positional-only parameter is specified with a default, the
following positional-only and positional-or-keyword parameters need to have
defaults as well.
* Positional-only parameters which do not have default
values are *required* positional-only parameters.
Therefore the following would be valid function definitions::
def name(p1, p2, /, p_or_kw, *, kw):
def name(p1, p2=None, /, p_or_kw=None, *, kw):
@ -420,7 +464,12 @@ valid signatures::
def name(p1, p2, /, p_or_kw):
def name(p1, p2, /):
While the followings are not::
Just like today, the following would be valid function definitions::
def name(p_or_kw, *, kw):
def name(*, kw):
While the following would be invalid::
def name(p1, p2=None, /, p_or_kw, *, kw):
def name(p1=None, p2, /, p_or_kw=None, *, kw):
@ -430,21 +479,40 @@ While the followings are not::
Full grammar specification
--------------------------
A draft of the proposed grammar specification is::
A simplified view of the proposed grammar specification is::
new_typedargslist:
tfpdef ['=' test] (',' tfpdef ['=' test])* ',' '/' [',' [typedargslist]] | typedargslist
typedargslist:
tfpdef ['=' test] (',' tfpdef ['=' test])* ',' '/' [',' # and so on
new_varargslist:
vfpdef ['=' test] (',' vfpdef ['=' test])* ',' '/' [',' [varargslist]] | varargslist
varargslist:
vfpdef ['=' test] (',' vfpdef ['=' test])* ',' '/' [',' # and so on
It would be added to the actual ``typedargslist`` and ``varargslist``, but for
more relaxed discussion it is presented as ``new_typedargslist`` and
``new_varargslist``. Note that using a construction with two new rules
(``new_varargslist`` and ``new_varargslist``) is not possible with the current
parser as a rule is not LL(1). This is the reason the rule needs to be
included in the existing ``typedargslist`` and ``varargslist`` (in the same way
keyword-only arguments were introduced).
Based on the reference implementation in this PEP, the new rule for
``typedarglist`` would be::
typedargslist: (tfpdef ['=' test] (',' tfpdef ['=' test])* ',' '/' [',' [tfpdef ['=' test] (',' tfpdef ['=' test])* [',' [
'*' [tfpdef] (',' tfpdef ['=' test])* [',' ['**' tfpdef [',']]]
| '**' tfpdef [',']]]
| '*' [tfpdef] (',' tfpdef ['=' test])* [',' ['**' tfpdef [',']]]
| '**' tfpdef [',']] ] )| (
tfpdef ['=' test] (',' tfpdef ['=' test])* [',' [
'*' [tfpdef] (',' tfpdef ['=' test])* [',' ['**' tfpdef [',']]]
| '**' tfpdef [',']]]
| '*' [tfpdef] (',' tfpdef ['=' test])* [',' ['**' tfpdef [',']]]
| '**' tfpdef [','])
and for ``varargslist`` would be::
varargslist: vfpdef ['=' test ](',' vfpdef ['=' test])* ',' '/' [',' [ (vfpdef ['=' test] (',' vfpdef ['=' test])* [',' [
'*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]]
| '**' vfpdef [',']]]
| '*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]]
| '**' vfpdef [',']) ]] | (vfpdef ['=' test] (',' vfpdef ['=' test])* [',' [
'*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]]
| '**' vfpdef [',']]]
| '*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]]
| '**' vfpdef [',']
)
--------------------------------
Origin of the "/" as a separator
@ -460,32 +528,30 @@ in 2012 [#GUIDO]_ :
How to teach this
=================
Since this concept is closely analogous to keyword-only arguments, introducing
a dedicated syntax to mark positional-only arguments may in fact make it
*easier* to teach the possible function definitions a user may encounter or
design, by teaching the two concepts together.
Introducing a dedicated syntax to mark positional-only parameters is closely
analogous to existing keyword-only arguments. Teaching these concepts together
may *simplify* how to teach the possible function definitions a user may encounter or
design.
This PEP recommends adding a new subsection to the Python documentation, in the
section `"More on Defining Functions"`_, where the rest of the argument types
are discussed. The following paragraphs serve as a draft for these additions
that will serve to introduce the notation for both positional-only and
keyword-only parameters. It does not intend to be exhaustive, nor should it be
are discussed. The following paragraphs serve as a draft for these additions.
They will introduce the notation for both positional-only and
keyword-only parameters. It is not intended to be exhaustive, nor should it be
considered the final version to be incorporated into the documentation.
.. _"More on Defining Functions": https://docs.python.org/3.7/tutorial/controlflow.html#more-on-defining-functions
-------------------------------------------------------------------------------
By default, all arguments passed to a Python function can be either by position
or explicitly by keyword. Occasionally, it makes sense to restrict the way
arguments can be passed. To this end, it is possible to mark certain parameters
as *positional-only*, meaning that they cannot be passed by keyword. This can
be achieved by placing a ``/`` (forward-slash) in the arguments list after the
last positional-only parameter. In order to mark parameters as *keyword-only*,
meaning that they can *only* be passed by keyword argument, place a ``*`` in
the arguments list before the first keyword-only parameter.
By default, arguments may be passed to a Python function either by position
or explicitly by keyword. For readability and performance, it makes sense to
restrict the way arguments can be passed so that a developer need only look
at the function definition to determine if items are passed by position, by
position or keyword, or by keyword.
A function definition which makes use of both of these features may look like::
A function definition may look like::
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
----------- ---------- ----------
@ -494,7 +560,46 @@ A function definition which makes use of both of these features may look like::
| - Keyword only
-- Positional only
Consider the following example functions::
where ``/`` and ``*`` are optional. If used, these symbols indicate the kind of
parameter by how the arguments may be passed to the function:
positional-only, positional-or-keyword, and keyword-only. Keyword parameters
are also referred to as named parameters.
-------------------------------
Positional-or-Keyword Arguments
-------------------------------
If ``/`` and ``*`` are not present in the function definition, arguments may
be passed to a function by position or by keyword.
--------------------------
Positional-only Parameters
--------------------------
Looking at this in a bit more detail, it is possible to mark certain parameters
as *positional-only*. If *positional-only*, the parameters' order matters, and
the parameters cannot be passed by keyword. Positional-only parameters would
be placed before a ``/`` (forward-slash). The ``/`` is used to logically
separate the positional-only parameters from the rest of the parameters.
If there is no ``/`` in the function definition, there are no positional-only
parameters.
Parameters following the ``/`` may be *positional-or-keyword* or *keyword-only*.
----------------------
Keyword-only Arguments
----------------------
To mark parameters as *keyword-only*, indicating the parameters must be passed
by keyword argument, place an ``*`` in the arguments list just before the first
*keyword-only* parameter.
-----------------
Function Examples
-----------------
Consider the following example function definitions paying close attention to the
markers ``/`` and ``*``::
>>> def standard_arg(arg):
... print(arg)
@ -509,28 +614,35 @@ Consider the following example functions::
... print(pos_only, standard, kwd_only)
The first places no restrictions on the calling convention::
The first function definition ``standard_arg``, the most familiar form,
places no restrictions on the calling convention and arguments may be
passed by position or keyword::
>>> standard_arg(2)
2
>>> standard_arg(arg=2)
2
The second is restricted to only use positional arguments::
The second function ``pos_only_arg` is restricted to only use positional
parameters as there is a ``/`` in the function definition::
>>> pos_only_arg(1)
1
>>> pos_only_arg(arg=1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: pos_only_arg() got an unexpected keyword argument 'arg'
The third only allows keyword arguments::
The third function ``kwd_only_args`` only allows keyword arguments as indicated
by a ``*`` in the function definition::
>>> kwd_only_arg(3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: kwd_only_arg() takes 0 positional arguments but 1 was given
>>> kwd_only_arg(arg=3)
3
@ -541,15 +653,32 @@ definition::
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: combined_example() takes 2 positional arguments but 3 were given
>>> combined_example(1, 2, kwd_only=3)
1 2 3
>>> combined_example(1, standard=2, kwd_only=3)
1 2 3
>>> combined_example(pos_only=1, standard=2, kwd_only=3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: combined_example() got an unexpected keyword argument 'pos_only'
-----
Recap
-----
The use case will determine which parameters to use in the function definition::
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
As guidance:
* Use positional-only if names do not matter or have no meaning, and there are
only a few arguments which will always be passed in the same order.
* Use keyword-only when names have meaning and the function definition is
more understandable by being explicit with names.
========================
Reference Implementation
@ -572,7 +701,7 @@ Do Nothing
----------
Always an option — the status quo. While this was considered, the
aforementioned benefits is worth the additional complexity to the language.
aforementioned benefits are worth the addition to the language.
----------
Decorators
@ -586,10 +715,10 @@ additional syntax. However, we have decided to reject this idea because:
* It introduces an asymmetry with how parameter behavior is declared.
* It makes it difficult to safely for static analyzers and type checkers to
* It makes it difficult for static analyzers and type checkers to
safely identify positional-only parameters. They would need to query the AST
for the list of decorators and identify the correct one by name or with extra
heuristics, whereas opposed to how keyword-only parameters are exposed
heuristics, while keyword-only parameters are exposed
directly in the AST. In order for tools to correctly identify
positional-only parameters, they would need to execute the module to access
any metadata the decorator is setting.
@ -640,8 +769,8 @@ a new syntax because:
* It is not symmetric with how the keyword-only parameters are currently
declared.
* Querying the AST for positional-only parameters would require checking the
normal arguments and inspecting their names, whereas keyword-only parameters
* Querying the AST for positional-only parameters would require checking the
normal arguments and inspecting their names, whereas keyword-only parameters
have a property associated with them (``FunctionDef.args.kwonlyargs``).
* Every parameter would need to be inspected to know when positional-only
@ -682,6 +811,7 @@ reasons:
------------------------
After separator proposal
------------------------
Demarcating positional-parameters after the ``/`` was another consideration.
However, we were unable to find an approach which would modify the arguments
after the marker. Otherwise, would force the parameters before the marker to