PEP 736: Address first round of feedback (#3639)
Co-authored-by: Erlend E. Aasland <erlend.aasland@protonmail.com> Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
This commit is contained in:
parent
d3e304e8d6
commit
f1d490fdd0
|
@ -615,7 +615,7 @@ peps/pep-0732.rst @Mariatta
|
||||||
peps/pep-0733.rst @encukou @vstinner @zooba @iritkatriel
|
peps/pep-0733.rst @encukou @vstinner @zooba @iritkatriel
|
||||||
peps/pep-0734.rst @ericsnowcurrently
|
peps/pep-0734.rst @ericsnowcurrently
|
||||||
peps/pep-0735.rst @brettcannon
|
peps/pep-0735.rst @brettcannon
|
||||||
peps/pep-0736.rst @gvanrossum @Rosuav
|
peps/pep-0736.rst @Rosuav
|
||||||
peps/pep-0737.rst @vstinner
|
peps/pep-0737.rst @vstinner
|
||||||
peps/pep-0738.rst @encukou
|
peps/pep-0738.rst @encukou
|
||||||
peps/pep-0740.rst @dstufft
|
peps/pep-0740.rst @dstufft
|
||||||
|
|
|
@ -2,21 +2,20 @@ PEP: 736
|
||||||
Title: Shorthand syntax for keyword arguments at invocation
|
Title: Shorthand syntax for keyword arguments at invocation
|
||||||
Author: Joshua Bambrick <jbambrick@google.com>,
|
Author: Joshua Bambrick <jbambrick@google.com>,
|
||||||
Chris Angelico <rosuav@gmail.com>
|
Chris Angelico <rosuav@gmail.com>
|
||||||
Sponsor: Guido van Rossum <guido@python.org>
|
|
||||||
Discussions-To: https://discuss.python.org/t/pep-736-shorthand-syntax-for-keyword-arguments-at-invocation/43432
|
Discussions-To: https://discuss.python.org/t/pep-736-shorthand-syntax-for-keyword-arguments-at-invocation/43432
|
||||||
Status: Draft
|
Status: Draft
|
||||||
Type: Standards Track
|
Type: Standards Track
|
||||||
Created: 28-Nov-2023
|
Created: 28-Nov-2023
|
||||||
Python-Version: 3.13
|
Python-Version: 3.14
|
||||||
Post-History: `14-Oct-2023 <https://discuss.python.org/t/syntactic-sugar-to-encourage-use-of-named-arguments/36217>`__,
|
Post-History: `14-Oct-2023 <https://discuss.python.org/t/syntactic-sugar-to-encourage-use-of-named-arguments/36217>`__,
|
||||||
`17-Jan-2024 <https://discuss.python.org/t/pep-736-shorthand-syntax-for-keyword-arguments-at-invocation/43432>`__,
|
`17-Jan-2024 <https://discuss.python.org/t/pep-736-shorthand-syntax-for-keyword-arguments-at-invocation/43432>`__,
|
||||||
|
|
||||||
Abstract
|
Abstract
|
||||||
========
|
========
|
||||||
|
|
||||||
This PEP proposes introducing syntactic sugar ``f(x=)`` for the common
|
This PEP proposes introducing syntactic sugar ``f(x=)`` for the pattern
|
||||||
pattern where a named argument is the same as the name of the variable
|
where a named argument is the same as the name of the variable corresponding to
|
||||||
corresponding to its value ``f(x=x)``.
|
its value ``f(x=x)``.
|
||||||
|
|
||||||
Motivation
|
Motivation
|
||||||
==========
|
==========
|
||||||
|
@ -33,9 +32,8 @@ Consider the following call:
|
||||||
)
|
)
|
||||||
|
|
||||||
The case of a keyword argument name matching the variable name of its value is
|
The case of a keyword argument name matching the variable name of its value is
|
||||||
prevalent among all major Python libraries. This verbosity and redundancy
|
prevalent among Python libraries. This verbosity and redundancy discourages
|
||||||
discourages use of named arguments and reduces readability by increasing visual
|
use of named arguments and reduces readability by increasing visual noise.
|
||||||
noise.
|
|
||||||
|
|
||||||
Rationale
|
Rationale
|
||||||
=========
|
=========
|
||||||
|
@ -49,18 +47,17 @@ and visual noise.
|
||||||
We contend that a simple syntactic sugar used to simplify this common pattern
|
We contend that a simple syntactic sugar used to simplify this common pattern
|
||||||
which would confer numerous benefits:
|
which would confer numerous benefits:
|
||||||
|
|
||||||
Encourages use of named variables
|
Encourages use of named arguments
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
||||||
This syntax would encourage the use of named variables, thereby increasing
|
This syntax would encourage the use of named arguments, thereby increasing
|
||||||
readability (*explicit is better than implicit*) and reducing bugs from argument
|
readability and reducing bugs from argument transposition.
|
||||||
transposition.
|
|
||||||
|
|
||||||
Reduces verbosity
|
Reduces verbosity
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
By minimising visual noise and in some cases lines of code, we can increase
|
By minimising visual noise and in some cases lines of code, we can increase
|
||||||
readability (*readability counts*).
|
readability.
|
||||||
|
|
||||||
Encourages consistent variable names
|
Encourages consistent variable names
|
||||||
------------------------------------
|
------------------------------------
|
||||||
|
@ -68,13 +65,42 @@ Encourages consistent variable names
|
||||||
A common problem is that semantically identical variables have different names
|
A common problem is that semantically identical variables have different names
|
||||||
depending on their contexts. This syntax would encourage authors to use the same
|
depending on their contexts. This syntax would encourage authors to use the same
|
||||||
variable name when calling a function as the argument name, which would increase
|
variable name when calling a function as the argument name, which would increase
|
||||||
consistency of variable names used and hence also *readability*.
|
consistency of variable names used and hence also readability.
|
||||||
|
|
||||||
|
Highlights arguments not following this pattern
|
||||||
|
-----------------------------------------------
|
||||||
|
|
||||||
|
With the current syntax, function calls where many arguments are forwarded from
|
||||||
|
the local context can make other argument values easy to miss due to the visual
|
||||||
|
noise. For example::
|
||||||
|
|
||||||
|
add_middleware(
|
||||||
|
excluded_urls=excluded_urls,
|
||||||
|
server_request=server_request,
|
||||||
|
client_request=client_request,
|
||||||
|
client_response=client_response,
|
||||||
|
span_details=_get_span_details(),
|
||||||
|
tracer=tracer,
|
||||||
|
meter=meter,
|
||||||
|
)
|
||||||
|
|
||||||
|
With this syntax, the exceptional arguments become easier to identify::
|
||||||
|
|
||||||
|
add_middleware(
|
||||||
|
excluded_urls=,
|
||||||
|
server_request=,
|
||||||
|
client_request=,
|
||||||
|
client_response=,
|
||||||
|
span_details=_get_span_details(),
|
||||||
|
tracer=,
|
||||||
|
meter=,
|
||||||
|
)
|
||||||
|
|
||||||
Applicability to dictionary construction
|
Applicability to dictionary construction
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
|
||||||
This syntax can be applied to dictionary construction where a similar
|
This syntax can be applied to dictionary construction where a similar pattern
|
||||||
pattern frequently occurs (where dictionary keys are identical the names of the
|
frequently occurs (where dictionary keys are identical the names of the
|
||||||
variables assigned as their values), ``{"x": x, "y": y}`` or ``dict(x=x, y=y)``.
|
variables assigned as their values), ``{"x": x, "y": y}`` or ``dict(x=x, y=y)``.
|
||||||
With this feature, this can now also be trivially written as ``dict(x=, y=)``.
|
With this feature, this can now also be trivially written as ``dict(x=, y=)``.
|
||||||
Whether to further support similar syntax in dictionary literals is an open
|
Whether to further support similar syntax in dictionary literals is an open
|
||||||
|
@ -104,13 +130,13 @@ Will be interpreted exactly equivalently to following in existing syntax:
|
||||||
If no variable matches that name in the invocation scope, a ``NameError`` is
|
If no variable matches that name in the invocation scope, a ``NameError`` is
|
||||||
raised in an identical manner as would be with the established expanded syntax.
|
raised in an identical manner as would be with the established expanded syntax.
|
||||||
|
|
||||||
This proposal only pertains to function invocations; function defintions are
|
This proposal only pertains to function invocations; function definitions are
|
||||||
unaffected by the syntax change. All existing valid syntax is unchanged.
|
unaffected by the syntax change. All existing valid syntax is unchanged.
|
||||||
|
|
||||||
Backwards Compatibility
|
Backwards Compatibility
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
Only new syntax is added which was previously syntactically erroreous. No
|
Only new syntax is added which was previously syntactically erroneous. No
|
||||||
existing valid syntax is modified. As such, the changes proposed are fully
|
existing valid syntax is modified. As such, the changes proposed are fully
|
||||||
backwards compatible.
|
backwards compatible.
|
||||||
|
|
||||||
|
@ -132,26 +158,35 @@ Prior Art
|
||||||
=========
|
=========
|
||||||
|
|
||||||
Python already possesses a very similar feature in f-string interpolation where
|
Python already possesses a very similar feature in f-string interpolation where
|
||||||
``f'{x=}'`` is effectively expanded to ``f'x={x}'`` [1]_.
|
``f'{x=}'`` is effectively expanded to ``f'x={x}'`` (see
|
||||||
|
`related GitHub issue <https://github.com/python/cpython/issues/80998>`__).
|
||||||
|
|
||||||
Several modern languages provide similar features during function invocation,
|
Several modern languages provide similar features during function invocation,
|
||||||
sometimes referred to as 'punning'. For example:
|
sometimes referred to as 'punning'. For example:
|
||||||
|
|
||||||
* In Ruby, ``f(x:, y:)`` is syntactic sugar for ``f(x: x, y: y)`` [2]_.
|
* In Ruby, ``f(x:, y:)`` is syntactic sugar for ``f(x: x, y: y)``. See the
|
||||||
* In ReasonML, ``f(~x, ~y)`` is syntactic sugar for ``f(~x=x, ~y=y)`` [3]_.
|
`Ruby 3.1.0 release notes <https://www.ruby-lang.org/en/news/2021/12/25/ruby-3-1-0-released/#:~:text=Other%20Notable%20New%20Features>`__ (search for "keyword arguments").
|
||||||
|
* In ReasonML, ``f(~x, ~y)`` is syntactic sugar for ``f(~x=x, ~y=y)``. See the
|
||||||
|
`ReasonML function documentation <https://reasonml.github.io/docs/en/function#function-application>`__ (search for "punning").
|
||||||
* In SystemVerilog, ``(.mult, .mop1, .data);`` is syntactic sugar for
|
* In SystemVerilog, ``(.mult, .mop1, .data);`` is syntactic sugar for
|
||||||
``(.mult(mult), .mop1(mop1), .data(data));`` [4]_.
|
``(.mult(mult), .mop1(mop1), .data(data));``. See
|
||||||
|
`SystemVerilog Implicit Port Connections <http://www.sunburst-design.com/papers/CummingsDesignCon2005_SystemVerilog_ImplicitPorts.pdf>`__.
|
||||||
|
* In Jakt, ``f(x, y)`` is syntactic sugar for ``f(x: x, y: y)``. See
|
||||||
|
`The Jakt programming language <https://github.com/SerenityOS/jakt?tab=readme-ov-file#function-calls>`__.
|
||||||
|
|
||||||
Beyond function invocation specifically, more languages offer similar features:
|
Beyond function invocation specifically, more languages offer similar features:
|
||||||
|
|
||||||
* In OCaml, ``let+ x in …`` is syntactic sugar for ``let+ x = x in …`` [5]_.
|
* In OCaml, ``let+ x in …`` is syntactic sugar for ``let+ x = x in …``. See
|
||||||
* In JavaScript, ``{ x, y }`` is syntactic sugar for ``{x: x, y: y}`` [6]_.
|
`OCaml Short notation for variable bindings (let-punning) <https://v2.ocaml.org/manual/bindingops.html#ss:letops-punning>`__.
|
||||||
* In Rust, ``User { x, y }`` is shorthand for ``User {x: x, y: y}`` [7]_.
|
* In JavaScript, ``{ x, y }`` is syntactic sugar for ``{x: x, y: y}``. See
|
||||||
|
`JavaScript Object Initializer <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer>`__.
|
||||||
|
* In Rust, ``User { x, y }`` is shorthand for ``User {x: x, y: y}``. See
|
||||||
|
`Rust Using the Field Init Shorthand <https://doc.rust-lang.org/book/ch05-01-defining-structs.html#using-the-field-init-shorthand-when-variables-and-fields-have-the-same-name>`__.
|
||||||
|
|
||||||
Applicability
|
Applicability
|
||||||
=============
|
=============
|
||||||
|
|
||||||
We analysed popular Python libraries using
|
We analysed popular Python libraries from the last few years using
|
||||||
`this script <https://gist.github.com/joshuabambrick/a850d0e0050129b9252c748fa06c48b2>`__
|
`this script <https://gist.github.com/joshuabambrick/a850d0e0050129b9252c748fa06c48b2>`__
|
||||||
to compute:
|
to compute:
|
||||||
|
|
||||||
|
@ -161,18 +196,22 @@ to compute:
|
||||||
* The number of lines of code which could be saved by using this syntactic sugar
|
* The number of lines of code which could be saved by using this syntactic sugar
|
||||||
to reduce the need for line wraps.
|
to reduce the need for line wraps.
|
||||||
|
|
||||||
===================================================================== ================ ============== =============== =====================
|
The purpose of this exercise was to compute statistics about the prevalence of
|
||||||
Statistic `cpython <a_>`__ `numpy <b_>`__ `pandas <c_>`__ `scikit-learn <d_>`__
|
this pattern and should not be interpreted as a recommendation that the proposed
|
||||||
===================================================================== ================ ============== =============== =====================
|
syntactic sugar should be applied universally.
|
||||||
Number of keyword arguments of the form ``f(x=x)`` at invocation 4,225 2,768 13,235 8,342
|
|
||||||
Percentage of keyword arguments of the form ``f(x=x)`` at invocation 11.06% 13.17% 17.24% 18.64%
|
|
||||||
Lines saved 290 247 935 794
|
|
||||||
===================================================================== ================ ============== =============== =====================
|
|
||||||
|
|
||||||
.. _a: https://github.com/python/cpython/pull/111423/
|
===================================================================== =============== ================ ============== ==============
|
||||||
.. _b: https://github.com/numpy/numpy/pull/25021/
|
Statistic `polars <a_>`__ `fastapi <b_>`__ `rich <c_>`__ `httpx <d_>`__
|
||||||
.. _c: https://github.com/pandas-dev/pandas/pull/55744/
|
===================================================================== =============== ================ ============== ==============
|
||||||
.. _d: https://github.com/scikit-learn/scikit-learn/pull/27680/
|
Number of keyword arguments of the form ``f(x=x)`` at invocation 1,654 1,408 566 759
|
||||||
|
Percentage of keyword arguments of the form ``f(x=x)`` at invocation 15.83% 28.11% 15.74% 45.13%
|
||||||
|
Lines saved 170 35 62 117
|
||||||
|
===================================================================== =============== ================ ============== ==============
|
||||||
|
|
||||||
|
.. _a: https://github.com/joshuabambrick/polars/pull/1
|
||||||
|
.. _b: https://github.com/joshuabambrick/fastapi/pull/1
|
||||||
|
.. _c: https://github.com/joshuabambrick/rich/pull/1
|
||||||
|
.. _d: https://github.com/joshuabambrick/httpx/pull/1
|
||||||
|
|
||||||
Based on this, we note that the ``f(x=x)`` keyword argument pattern is
|
Based on this, we note that the ``f(x=x)`` keyword argument pattern is
|
||||||
widespread, accounting for 10-20% of all keyword argument uses.
|
widespread, accounting for 10-20% of all keyword argument uses.
|
||||||
|
@ -181,16 +220,17 @@ Proposed Syntax
|
||||||
===============
|
===============
|
||||||
|
|
||||||
While this feature has been proposed on numerous occasions with several
|
While this feature has been proposed on numerous occasions with several
|
||||||
different forms [8]_ [9]_ [10]_ [11]_ [12]_, [13]_ we have opted to advocate
|
different forms [1]_ [2]_ [3]_ [4]_ [5]_, [6]_ we have opted to advocate
|
||||||
for the ``f(x=)`` form for the following reasons:
|
for the ``f(x=)`` form for the following reasons:
|
||||||
|
|
||||||
* This feature has been proposed frequently over a ten year period with the
|
* This feature has been proposed frequently over a ten year period with the
|
||||||
``f(x=)`` or ``f(=x)`` being by far the most common syntax [8]_ [9]_ [13]_.
|
``f(x=)`` or ``f(=x)`` being by far the most common syntax [1]_ [2]_ [6]_.
|
||||||
This is a strong indicator that it is the obvious notation.
|
This is a strong indicator that it is the obvious notation.
|
||||||
* The proposed syntax closely matches the f-string debug ``f'{var=}'`` syntax
|
* The proposed syntax closely matches the f-string debug ``f'{var=}'`` syntax
|
||||||
(established Pythonic style) and serves an almost identical purpose.
|
(established Pythonic style) and serves an almost identical purpose.
|
||||||
* The proposed syntax is exactly analogous to the Ruby keyword argument
|
* The proposed syntax is exactly analogous to the Ruby keyword argument
|
||||||
syntactic sugar [2]_.
|
syntactic sugar. See the
|
||||||
|
`Ruby 3.1.0 release notes <https://www.ruby-lang.org/en/news/2021/12/25/ruby-3-1-0-released/#:~:text=Other%20Notable%20New%20Features>`__ (search for "keyword arguments").
|
||||||
* The syntax is easy to implement as it is simple syntactic sugar.
|
* The syntax is easy to implement as it is simple syntactic sugar.
|
||||||
* When compared to the prefix form (see `Rejected Ideas`_), this syntax
|
* When compared to the prefix form (see `Rejected Ideas`_), this syntax
|
||||||
communicates "here is a parameter, go find its argument" which is more
|
communicates "here is a parameter, go find its argument" which is more
|
||||||
|
@ -205,6 +245,33 @@ Many alternative syntaxes have been proposed however no syntax other than
|
||||||
``f(=x)`` or ``f(x=)`` has garnered significant support. We here enumerate some
|
``f(=x)`` or ``f(x=)`` has garnered significant support. We here enumerate some
|
||||||
of the most popular proposed alternatives and why we ultimately reject them.
|
of the most popular proposed alternatives and why we ultimately reject them.
|
||||||
|
|
||||||
|
``f(a, b, *, x)``
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
On a few occasions the idea has been floated to borrow the syntax from
|
||||||
|
keyword-only function definitions.
|
||||||
|
|
||||||
|
In favour of this proposal:
|
||||||
|
|
||||||
|
* This syntax is familiar from its use to require keyword-only arguments in
|
||||||
|
function definitions.
|
||||||
|
* `A poll of Python developers <https://discuss.python.org/t/syntactic-sugar-to-encourage-use-of-named-arguments/36217/130>`__
|
||||||
|
indicates that this is the second most popular syntax among those proposed.
|
||||||
|
|
||||||
|
However, we object that:
|
||||||
|
|
||||||
|
* For any given argument, it is less clear from local context whether it is
|
||||||
|
positional or named. The ``*`` could easily be missed in a long argument list
|
||||||
|
and named arguments may be read as positional or vice versa.
|
||||||
|
* It is unclear whether keyword arguments for which the value was not elided may
|
||||||
|
follow the ``*``. If so, then their relative position will be inconsistent but
|
||||||
|
if not, then an arbitrary grouping is enforced between different types of
|
||||||
|
keyword arguments and reordering would be necessary if only one name was
|
||||||
|
changed.
|
||||||
|
* The use of ``*`` in function calls is established and this proposal would
|
||||||
|
introduce a new effect which could cause confusion. For example,
|
||||||
|
``f(a, *x, y)`` would mean something different than ``f(a, *, x, y)``.
|
||||||
|
|
||||||
``f(=x)``
|
``f(=x)``
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
@ -223,10 +290,10 @@ On the contrary:
|
||||||
this feature to shout its presence any more than a typical named argument. By
|
this feature to shout its presence any more than a typical named argument. By
|
||||||
the time we read to the ``=`` it is clear that the value is filled in
|
the time we read to the ``=`` it is clear that the value is filled in
|
||||||
automatically just as the value is clear in the typical keyword argument case.
|
automatically just as the value is clear in the typical keyword argument case.
|
||||||
* Semantically, this form communicates 'here is a value, fill in the parameter'.
|
* Semantically, this form communicates 'here is a value, fill in the parameter'
|
||||||
* which is not what we want to convey.
|
which is not what we want to convey.
|
||||||
* Less similar to f-string syntax.
|
* It is less similar to f-string syntax.
|
||||||
* Less obvious that arbitrary expressions are invalid, e.g. ``f(=a+b)``.
|
* It is less obvious that arbitrary expressions are invalid, e.g. ``f(=a + b)``.
|
||||||
|
|
||||||
``f(%x)`` or ``f(:x)`` or ``f(.x)``
|
``f(%x)`` or ``f(:x)`` or ``f(.x)``
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
@ -237,23 +304,6 @@ traction and the choice of symbol seems arbitrary compared to ``=``.
|
||||||
Additionally, there is less precedent in terms of existing language features
|
Additionally, there is less precedent in terms of existing language features
|
||||||
(such as f-string) or other languages (such as Ruby).
|
(such as f-string) or other languages (such as Ruby).
|
||||||
|
|
||||||
``f(a, b, *, x)``
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
On a few occasions the idea has been floated to borrow the syntax from
|
|
||||||
keyword-only function definitions. This is less arbitrary than ``f(%x)`` or
|
|
||||||
variants, but no less so than ``f(x=)``.
|
|
||||||
|
|
||||||
However, we object that:
|
|
||||||
|
|
||||||
* For any given argument, it is less clear from local context whether it is
|
|
||||||
positional or named. The ``*`` could easily be missed in a long argument list
|
|
||||||
and named arguments may be read as positional or vice versa.
|
|
||||||
* It is unclear whether keyword arguments for which the value was not elided may
|
|
||||||
follow the ``*``. If so, then their relative position will be inconsistent but
|
|
||||||
if not, then an arbitrary grouping is enforced between different types of
|
|
||||||
keyword arguments.
|
|
||||||
|
|
||||||
Objections
|
Objections
|
||||||
==========
|
==========
|
||||||
|
|
||||||
|
@ -267,7 +317,7 @@ The syntax is ugly
|
||||||
|
|
||||||
This objection is by far the most common. On the contrary, we argue that:
|
This objection is by far the most common. On the contrary, we argue that:
|
||||||
|
|
||||||
* This objection is is subjective and many community members disagree.
|
* This objection is subjective and many community members disagree.
|
||||||
* A nearly-identical syntax is already established for f-strings.
|
* A nearly-identical syntax is already established for f-strings.
|
||||||
* Programmers will, as ever, adjust over time.
|
* Programmers will, as ever, adjust over time.
|
||||||
|
|
||||||
|
@ -282,18 +332,27 @@ We argue that:
|
||||||
* The expansion of ``x=`` to ``x=x`` is in fact a trivial feature and inherently
|
* The expansion of ``x=`` to ``x=x`` is in fact a trivial feature and inherently
|
||||||
significantly less complex than ``*arg`` and ``**kwarg`` expansion.
|
significantly less complex than ``*arg`` and ``**kwarg`` expansion.
|
||||||
* This particular syntactic form has been independently proposed on numerous
|
* This particular syntactic form has been independently proposed on numerous
|
||||||
occasions, indicating that it is the most obvious [8]_ [9]_ [13]_.
|
occasions, indicating that it is the most obvious [1]_ [2]_ [6]_.
|
||||||
|
|
||||||
The feature is not explicit
|
The feature is not explicit
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
This is based on a misunderstanding of the Zen of Python. Keyword arguments are
|
We recognise that, in an obvious sense, the argument value is 'implicit' in this
|
||||||
fundamentally more explicit than positional ones where argument assignment is
|
proposed syntax. However, we do not think that this is what the Zen of Python is
|
||||||
only visible at the function definition. On the contrary, the proposed syntactic
|
aiming to discourage.
|
||||||
sugar contains all the information as is conveyed by the established keyword
|
|
||||||
argument syntax but without the redundancy. Moreover, the introduction of this
|
In the sense that we take the Zen to be referring to, keyword arguments (for
|
||||||
syntactic sugar incentivises use of keyword arguments, making typical Python
|
example) are more explicit than positional arguments where the argument name is
|
||||||
codebases more explicit.
|
omitted and impossible to tell from the local context. Conversely, the syntactic
|
||||||
|
sugar for integers ``x += 1`` is not more implicit than ``x = x + 1`` in this
|
||||||
|
sense, even though the variable is omitted from the right hand side, because it
|
||||||
|
is immediately obvious from the local context what it is.
|
||||||
|
|
||||||
|
The syntax proposed in this PEP is much more closely analogous to the ``x += 1``
|
||||||
|
example (although simpler since we do not propose to introduce a new operation).
|
||||||
|
Moreover, the introduction of this syntactic sugar should encourage the use of
|
||||||
|
keyword arguments over positional ones, making typical Python codebases more
|
||||||
|
explicit in general.
|
||||||
|
|
||||||
The feature adds another way of doing things
|
The feature adds another way of doing things
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
|
@ -306,17 +365,115 @@ readable notation for the same way.
|
||||||
Renaming the variable in the calling context will break the code
|
Renaming the variable in the calling context will break the code
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
|
||||||
A ``NameError`` would make the mistake abundantly clear. Moreover, text editors
|
A ``NameError`` would make the mistake clear in most cases. There may be
|
||||||
could highlight this based on static analysis ‒ ``f(x=)`` is exactly equivalent
|
confusion if a variable from a broader scope has the same name as the original
|
||||||
to writing ``f(x=x)``. If ``x`` does not exist, modern editors have no problem
|
variable, so no ``NameError`` would be raised. However, this issue can also
|
||||||
highlighting the issue.
|
occur with keyword arguments using the current syntax (arguably, this syntactic
|
||||||
|
sugar could make it harder to spot). Moreover, having variables with the same
|
||||||
|
name in different scopes is broadly considered bad practice and discouraged by
|
||||||
|
linters.
|
||||||
|
|
||||||
Recommendations
|
Code editors could highlight the issue based on static analysis - ``f(x=)`` is
|
||||||
===============
|
exactly equivalent to writing ``f(x=x)``. If ``x`` does not exist, modern
|
||||||
|
editors have no problem highlighting the issue.
|
||||||
|
|
||||||
|
This syntax increases coupling
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
We recognise that, as ever, all syntax has the potential for misuse and so
|
||||||
|
should be applied judiciously to improve codebases. In this case, if a parameter
|
||||||
|
and its value have the same semantics in both contexts, that may suggest that
|
||||||
|
using this new syntax is appropriate and will help ameliorate the risk of
|
||||||
|
unintentional desynchronisation which harms readability.
|
||||||
|
|
||||||
|
However, if the two variables have different semantics, that may suggest that
|
||||||
|
this feature should not be used to encourage consistency or even that they
|
||||||
|
should be renamed.
|
||||||
|
|
||||||
|
Recommendations for using this syntax
|
||||||
|
=====================================
|
||||||
|
|
||||||
As with any other language feature, the programmer should exercise their own
|
As with any other language feature, the programmer should exercise their own
|
||||||
judgement about whether to use it in any given context. We do not recommend
|
judgement about whether it is prudent to use it in any given context. We do not
|
||||||
enforcing a rule to use the feature in all cases where it may be applicable.
|
recommend enforcing a rule to use the feature in all cases where it may be
|
||||||
|
applicable.
|
||||||
|
|
||||||
|
As described `above <This syntax increases coupling>`__, we propose that a
|
||||||
|
reasonable rule of thumb would be to use this in cases where a parameter and its
|
||||||
|
argument have the same semantics in order to reduce unintentional
|
||||||
|
desynchronisation without causing inappropriate coupling.
|
||||||
|
|
||||||
|
Impact on editing
|
||||||
|
=================
|
||||||
|
|
||||||
|
Using a plain text editor
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
Editing with a plain text editor should generally be unaffected.
|
||||||
|
|
||||||
|
When renaming a variable using a 'Find-Replace' method, where this syntax is
|
||||||
|
used the developer will come across the function argument at invocation (as they
|
||||||
|
would if this syntax was not used). At that point, they can as usual decide
|
||||||
|
whether to update the argument as well or expand to the full ``f(x=x)`` syntax.
|
||||||
|
|
||||||
|
As with the current syntax, a 'Find-Replace All' method would fail since the
|
||||||
|
keyword argument would not exist at function definition, in the vast majority
|
||||||
|
of cases.
|
||||||
|
|
||||||
|
If the developer leaves the argument name unchanged and forgets to update its
|
||||||
|
value, a ``NameError`` will typically be raised as described
|
||||||
|
`above <Renaming the variable in the calling context will break the code>`__.
|
||||||
|
|
||||||
|
Proposals for IDEs
|
||||||
|
------------------
|
||||||
|
|
||||||
|
In response to community feedback, we include some suggestions regarding how
|
||||||
|
IDEs could handle this syntax. However, we of course defer to the domain experts
|
||||||
|
developing IDEs to use their own discretion.
|
||||||
|
|
||||||
|
Most considerations are made simple by recognising that ``f(x=)`` is just
|
||||||
|
syntactic sugar for ``f(x=x)`` and should be treated the same as at present.
|
||||||
|
|
||||||
|
Highlighting NameErrors
|
||||||
|
'''''''''''''''''''''''
|
||||||
|
|
||||||
|
IDEs typically offer a feature to highlight code that may cause a ``NameError``.
|
||||||
|
We recommend that this syntax be treated similarly to the expanded form
|
||||||
|
``f(x=x)`` to identify and highlight cases where the elided value variable may
|
||||||
|
not exist. What visual cue may be used to highlight these cases may be the same
|
||||||
|
or different from that which would be used with the current syntax, depending on
|
||||||
|
the IDE.
|
||||||
|
|
||||||
|
Jump to definition
|
||||||
|
''''''''''''''''''
|
||||||
|
|
||||||
|
There are a few possible ways that a 'jump to definition' feature could be
|
||||||
|
implemented depending on the caret/cursor position.
|
||||||
|
|
||||||
|
One option is to:
|
||||||
|
|
||||||
|
* Jump to the argument in the function definition if the caret/cursor is on the
|
||||||
|
argument
|
||||||
|
* Jump to the definition of the elided variable if the caret/cursor is on the
|
||||||
|
character following the ``=`` in our proposed syntax.
|
||||||
|
|
||||||
|
Another, potentially complementary, option would be to expand the syntax
|
||||||
|
visually on mouseover and enable a ``Ctrl+Click`` (or ``Cmd+Click``) to the
|
||||||
|
definition of the variable.
|
||||||
|
|
||||||
|
Rename symbol
|
||||||
|
'''''''''''''
|
||||||
|
|
||||||
|
There are a few ways that IDEs may wish to support a 'Rename symbol' feature for
|
||||||
|
this syntax. For example, if the argument is being renamed, the IDE may:
|
||||||
|
|
||||||
|
* Also rename the variable used as its value in each calling context where this
|
||||||
|
syntax is used
|
||||||
|
* Expand to use the full syntax to pass the variable used as its value
|
||||||
|
* Prompt the developer to select between the two above options
|
||||||
|
|
||||||
|
The last option here seems most preferable in order to reduce unintentional
|
||||||
|
desynchronisation of names while highlighting the user to the changes.
|
||||||
|
|
||||||
Reference Implementation
|
Reference Implementation
|
||||||
========================
|
========================
|
||||||
|
@ -327,32 +484,18 @@ for cpython has been provided by @Hels15.
|
||||||
References
|
References
|
||||||
==========
|
==========
|
||||||
|
|
||||||
.. [1] Issue 36817: Add = to f-strings for easier debugging. - Python tracker
|
.. [1] Short form for keyword arguments and dicts (2013)
|
||||||
https://bugs.python.org/issue36817
|
|
||||||
.. [2] Ruby keyword argument syntactic sugar
|
|
||||||
https://www.ruby-lang.org/en/news/2021/12/25/ruby-3-1-0-released/#:~:text=Other%20Notable%20New%20Features
|
|
||||||
.. [3] ReasonML named argument punning
|
|
||||||
https://reasonml.github.io/docs/en/function#:~:text=Named%20argument%20punning
|
|
||||||
.. [4] SystemVerilog Implicit Port Connections
|
|
||||||
http://www.sunburst-design.com/papers/CummingsDesignCon2005_SystemVerilog_ImplicitPorts.pdf
|
|
||||||
.. [5] OCaml Short notation for variable bindings (let-punning)
|
|
||||||
https://v2.ocaml.org/manual/bindingops.html#ss:letops-punning
|
|
||||||
.. [6] JavaScript Object Initializer
|
|
||||||
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer
|
|
||||||
.. [7] Rust Using the Field Init Shorthand
|
|
||||||
https://doc.rust-lang.org/book/ch05-01-defining-structs.html#using-the-field-init-shorthand-when-variables-and-fields-have-the-same-name
|
|
||||||
.. [8] Short form for keyword arguments and dicts (2013)
|
|
||||||
https://mail.python.org/archives/list/python-ideas@python.org/thread/SQKZ273MYAY5WNIQRGEDLYTKVORVKNEZ/#LXMU22F63VPCF7CMQ4OQRH2CG6H7WCQ6
|
https://mail.python.org/archives/list/python-ideas@python.org/thread/SQKZ273MYAY5WNIQRGEDLYTKVORVKNEZ/#LXMU22F63VPCF7CMQ4OQRH2CG6H7WCQ6
|
||||||
.. [9] Keyword arguments self-assignment (2020)
|
.. [2] Keyword arguments self-assignment (2020)
|
||||||
https://mail.python.org/archives/list/python-ideas@python.org/thread/SIMIOC7OW6QKLJOTHJJVNNBDSXDE2SGV/
|
https://mail.python.org/archives/list/python-ideas@python.org/thread/SIMIOC7OW6QKLJOTHJJVNNBDSXDE2SGV/
|
||||||
.. [10] Shorthand notation of dict literal and function call (2020)
|
.. [3] Shorthand notation of dict literal and function call (2020)
|
||||||
https://discuss.python.org/t/shorthand-notation-of-dict-literal-and-function-call/5697/1
|
https://discuss.python.org/t/shorthand-notation-of-dict-literal-and-function-call/5697/1
|
||||||
.. [11] Allow identifiers as keyword arguments at function call site (extension
|
.. [4] Allow identifiers as keyword arguments at function call site (extension
|
||||||
of PEP 3102?) (2023)
|
of PEP 3102?) (2023)
|
||||||
https://discuss.python.org/t/allow-identifiers-as-keyword-arguments-at-function-call-site-extension-of-pep-3102/31677
|
https://discuss.python.org/t/allow-identifiers-as-keyword-arguments-at-function-call-site-extension-of-pep-3102/31677
|
||||||
.. [12] Shorten Keyword Arguments with Implicit Notation: foo(a=a, b=b) to foo(.a, .b) (2023)
|
.. [5] Shorten Keyword Arguments with Implicit Notation: foo(a=a, b=b) to foo(.a, .b) (2023)
|
||||||
https://discuss.python.org/t/shorten-keyword-arguments-with-implicit-notation-foo-a-a-b-b-to-foo-a-b/33080
|
https://discuss.python.org/t/shorten-keyword-arguments-with-implicit-notation-foo-a-a-b-b-to-foo-a-b/33080
|
||||||
.. [13] Syntactic sugar to encourage use of named arguments (2023)
|
.. [6] Syntactic sugar to encourage use of named arguments (2023)
|
||||||
https://discuss.python.org/t/syntactic-sugar-to-encourage-use-of-named-arguments/36217
|
https://discuss.python.org/t/syntactic-sugar-to-encourage-use-of-named-arguments/36217
|
||||||
|
|
||||||
Copyright
|
Copyright
|
||||||
|
|
Loading…
Reference in New Issue