@@ -2,20 +2,21 @@ PEP: 736
2
2
Title: Shorthand syntax for keyword arguments at invocation
3
3
Author: Joshua Bambrick <
[email protected] >,
4
4
Chris Angelico <
[email protected] >
5
- Discussions-To: https://discuss.python.org/t/pep-736-shorthand-syntax-for- keyword-arguments-at-invocation/43432
5
+ Discussions-To: https://discuss.python.org/t/pep-736-keyword-argument-shorthand-final-draft/58504
6
6
Status: Draft
7
7
Type: Standards Track
8
8
Created: 28-Nov-2023
9
9
Python-Version: 3.14
10
10
Post-History: `14-Oct-2023 <https://discuss.python.org/t/syntactic-sugar-to-encourage-use-of-named-arguments/36217 >`__,
11
11
`17-Jan-2024 <https://discuss.python.org/t/pep-736-shorthand-syntax-for-keyword-arguments-at-invocation/43432 >`__,
12
+ `17-Jul-2024 <https://discuss.python.org/t/pep-736-keyword-argument-shorthand-final-draft/58504 >`__,
12
13
13
14
Abstract
14
15
========
15
16
16
- This PEP proposes introducing syntactic sugar ``f(x=) `` for the pattern
17
- where a named argument is the same as the name of the variable corresponding to
18
- its value ``f(x=x) ``.
17
+ This PEP proposes to introduce syntactic sugar ``f(x=) `` for the common pattern
18
+ where a keyword argument has the same name as that of the variable corresponding
19
+ to its value ``f(x=x) ``.
19
20
20
21
Motivation
21
22
==========
@@ -32,25 +33,25 @@ Consider the following call:
32
33
)
33
34
34
35
The case of a keyword argument name matching the variable name of its value is
35
- prevalent among Python libraries. This verbosity and redundancy discourages
36
- use of named arguments and reduces readability by increasing visual noise.
36
+ prevalent among Python libraries. This redundancy discourages use of named
37
+ arguments and reduces readability by increasing visual noise.
37
38
38
39
Rationale
39
40
=========
40
41
41
42
There are two ways to invoke a function with arguments: by position and by
42
- keyword. Keyword arguments confer many benefits by being explicit, thus
43
- increasing readability and minimising the risk of inadvertent transposition. On
44
- the flipside, positional arguments are often used simply to minimise verbosity
45
- and visual noise.
43
+ keyword. By being explicit, keyword arguments increase readability and
44
+ minimise the risk of inadvertent transposition. On the flipside, positional
45
+ arguments are often preferred simply to minimise verbosity and visual noise.
46
46
47
47
We contend that a simple syntactic sugar used to simplify this common pattern
48
- which would confer numerous benefits:
48
+ would confer numerous benefits:
49
49
50
50
Encourages use of named arguments
51
51
---------------------------------
52
52
53
- This syntax would encourage the use of named arguments, thereby increasing
53
+ By reducing the visual noise that established keyword argument syntax can cause,
54
+ this syntax would encourage the use of named arguments, thereby increasing
54
55
readability and reducing bugs from argument transposition.
55
56
56
57
Reduces verbosity
@@ -65,7 +66,7 @@ Encourages consistent variable names
65
66
A common problem is that semantically identical variables have different names
66
67
depending on their contexts. This syntax would encourage authors to use the same
67
68
variable name when calling a function as the argument name, which would increase
68
- consistency of variable names used and hence also readability.
69
+ consistency of variable names used and hence improve readability.
69
70
70
71
Highlights arguments not following this pattern
71
72
-----------------------------------------------
@@ -104,7 +105,7 @@ frequently occurs (where dictionary keys are identical the names of the
104
105
variables assigned as their values), ``{"x": x, "y": y} `` or ``dict(x=x, y=y) ``.
105
106
With this feature, this can now also be trivially written as ``dict(x=, y=) ``.
106
107
Whether to further support similar syntax in dictionary literals is an open
107
- question out of the scope of this PEP.
108
+ question beyond the scope of this PEP.
108
109
109
110
Specification
110
111
=============
@@ -168,11 +169,11 @@ sometimes referred to as 'punning'. For example:
168
169
Beyond function invocation specifically, more languages offer similar features:
169
170
170
171
* In OCaml, ``let+ x in … `` is syntactic sugar for ``let+ x = x in … ``. See
171
- `OCaml Short notation for variable bindings (let-punning) <https://v2.ocaml.org/manual/bindingops.html#ss:letops-punning >`__.
172
+ `OCaml: Short notation for variable bindings (let-punning) <https://v2.ocaml.org/manual/bindingops.html#ss:letops-punning >`__.
172
173
* In JavaScript, ``{ x, y } `` is syntactic sugar for ``{x: x, y: y} ``. See
173
- `JavaScript Object Initializer <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer >`__.
174
+ `JavaScript: Object Initializer <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer >`__.
174
175
* In Rust, ``User { x, y } `` is shorthand for ``User {x: x, y: y} ``. See
175
- `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 >`__.
176
+ `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 >`__.
176
177
177
178
Applicability
178
179
=============
@@ -181,7 +182,8 @@ We analysed popular Python libraries from the last few years using
181
182
`this script <https://gist.github.com/joshuabambrick/a850d0e0050129b9252c748fa06c48b2 >`__
182
183
to compute:
183
184
184
- * The number of keyword arguments were of the form ``f(x=x) `` at invocation.
185
+ * The number of keyword arguments which were of the form ``f(x=x) `` at
186
+ invocation.
185
187
* The percentage of keyword arguments which had the form ``f(x=x) `` at
186
188
invocation.
187
189
* The number of lines of code which could be saved by using this syntactic sugar
@@ -192,7 +194,7 @@ this pattern and should not be interpreted as a recommendation that the proposed
192
194
syntactic sugar should be applied universally.
193
195
194
196
===================================================================== =============== ================ ============= ==============
195
- Statistic `polars <a _>`__ `fastapi <b _>`__ `rich <c _>`__ `httpx <d _>`__
197
+ Statistic `Polars <a _>`__ `FastAPI <b _>`__ `Rich <c _>`__ `HTTPX <d _>`__
196
198
===================================================================== =============== ================ ============= ==============
197
199
Number of keyword arguments of the form ``f(x=x) `` at invocation 1,654 1,408 566 759
198
200
Percentage of keyword arguments of the form ``f(x=x) `` at invocation 15.83% 28.11% 15.74% 45.13%
@@ -216,8 +218,8 @@ different forms [1]_ [2]_ [3]_ [4]_ [5]_, [6]_ we have opted to advocate
216
218
for the ``f(x=) `` form for the following reasons:
217
219
218
220
* This feature has been proposed frequently over a ten year period with the
219
- ``f(x=) `` or ``f(=x) `` being by far the most common syntax [1 ]_ [ 2 ]_ [ 6 ]_.
220
- This is a strong indicator that it is the obvious notation.
221
+ ``f(x=) `` or ``f(=x) `` being by far the most commonly suggested syntax [1 ]_
222
+ [ 2 ]_ [ 6 ]_. This strongly indicates that it is the most obvious notation.
221
223
* The proposed syntax closely matches the f-string debug ``f'{var=}' `` syntax
222
224
(established Pythonic style) and serves an almost identical purpose.
223
225
* The proposed syntax is exactly analogous to the Ruby keyword argument
@@ -253,11 +255,11 @@ could be written to help explain this feature to those searching for an
253
255
explanation.
254
256
255
257
A teacher may explain this feature to new Python programmers as, "where you see
256
- an argument followed by an equals sign, such as ``f(x=) ``, this represents a
257
- keyword argument where the name of the argument and its value are the same. This
258
- can be written equivalently in the expanded notation, ``f(x=x) ``." Depending on
259
- a student's background, a teacher might further compare this to equivalent
260
- syntax in other languages or Python's f-string syntax ``f"{x=}" ``.
258
+ an argument followed only by an equals sign, such as ``f(x=) ``, this represents
259
+ a keyword argument where the name of the argument and its value are the same.
260
+ This can be written equivalently in the expanded notation, ``f(x=x) ``."
261
+ Depending on a student's background, a teacher might further compare this to
262
+ equivalent syntax in other languages or to Python's f-string syntax ``f"{x=}" ``.
261
263
262
264
To understand this, a student of Python would need to be familiar with the
263
265
basics of functions in addition to the existing keyword argument syntax.
@@ -270,7 +272,7 @@ f-string syntax as well as similar features in other languages (see
270
272
Rejected Ideas
271
273
==============
272
274
273
- Many alternative syntaxes have been proposed however no syntax other than
275
+ Many alternative syntaxes have been proposed however no form other than
274
276
``f(=x) `` or ``f(x=) `` has garnered significant support. We here enumerate some
275
277
of the most popular proposed alternatives and why we ultimately reject them.
276
278
@@ -297,7 +299,7 @@ However, we object that:
297
299
arbitrary, but if not, then an arbitrary grouping is enforced between
298
300
different types of keyword arguments and reordering of arguments would be
299
301
necessary if only one name (the argument or its value) was changed.
300
- * The use of ``* `` in function calls is established and this proposal would
302
+ * The use of ``* `` in function calls is well established and this proposal would
301
303
introduce a new effect which could cause confusion. For example,
302
304
``f(a, *x, y) `` would mean something different than ``f(a, *, x, y) ``.
303
305
@@ -310,7 +312,7 @@ In favour of this form:
310
312
``**kwargs `` syntax for function calls.
311
313
* It draws more attention to itself when arguments are arranged vertically. In
312
314
particular, if the arguments are of different lengths it is harder to find the
313
- equal sign at the end. Moreover, since Python is read left to right, the use
315
+ equals sign at the end. Moreover, since Python is read left to right, the use
314
316
of this feature is clearer to the reader earlier on.
315
317
316
318
On the contrary:
@@ -322,7 +324,9 @@ On the contrary:
322
324
* Semantically, this form communicates 'here is a value, fill in the parameter'
323
325
which is not what we want to convey.
324
326
* It is less similar to f-string syntax.
325
- * It is less obvious that arbitrary expressions are invalid, e.g. ``f(=a + b) ``.
327
+ * It is less obvious that arbitrary expressions are invalid, for example,
328
+ ``f(=a + b) ``, since such expressions are acceptable after the equals sign in
329
+ the current keyword argument syntax but not before it.
326
330
327
331
``f(%x) `` or ``f(:x) `` or ``f(.x) ``
328
332
-----------------------------------
@@ -344,7 +348,7 @@ the following objections were the most common:
344
348
The syntax is ugly
345
349
------------------
346
350
347
- This objection is by far the most common. On the contrary, we argue that:
351
+ This objection is the most common. On the contrary, we argue that:
348
352
349
353
* This objection is subjective and many community members disagree.
350
354
* A nearly-identical syntax is already established for f-strings.
@@ -358,8 +362,9 @@ We argue that:
358
362
* Introducing new features typically has this impact temporarily.
359
363
* The syntax is very similar to the established ``f'{x=}' `` syntax.
360
364
* The feature and syntax are familiar from other popular modern languages.
361
- * The expansion of ``x= `` to ``x=x `` is in fact a trivial feature and inherently
362
- significantly less complex than ``*arg `` and ``**kwarg `` expansion.
365
+ * The expansion of ``x= `` to ``x=x `` is a trivial feature and inherently
366
+ significantly less complex than the popular ``*arg `` and ``**kwarg ``
367
+ expansions.
363
368
* This particular syntactic form has been independently proposed on numerous
364
369
occasions, indicating that it is the most obvious [1 ]_ [2 ]_ [6 ]_.
365
370
@@ -379,9 +384,10 @@ is immediately obvious from the local context what it is.
379
384
380
385
The syntax proposed in this PEP is much more closely analogous to the ``x += 1 ``
381
386
example (although simpler since we do not propose to introduce a new operation).
382
- Moreover, the introduction of this syntactic sugar should encourage the use of
383
- keyword arguments over positional ones, making typical Python codebases more
384
- explicit in general.
387
+ Moreover, by removing the barrier of visual noise introduced by the existing
388
+ keyword argument syntax, this syntactic sugar will encourage the use of keyword
389
+ arguments over positional ones, making typical Python codebases more explicit in
390
+ general.
385
391
386
392
The feature adds another way of doing things
387
393
--------------------------------------------
@@ -394,15 +400,15 @@ readable notation for the same way.
394
400
Renaming the variable in the calling context will break the code
395
401
----------------------------------------------------------------
396
402
397
- A ``NameError `` would make the mistake clear in most cases. There may be
398
- confusion if a variable from a broader scope has the same name as the original
399
- variable, so no ``NameError `` would be raised. However, this issue can also
400
- occur with keyword arguments using the current syntax (arguably, this syntactic
401
- sugar could make it harder to spot). Moreover, having variables with the same
402
- name in different scopes is broadly considered bad practice and discouraged by
403
- linters.
403
+ A ``NameError `` would make the mistake clear in the large majority cases. There
404
+ may be confusion if a variable from a broader scope has the same name as the
405
+ original variable, so no ``NameError `` would be raised. However, this issue can
406
+ also occur with keyword arguments using the current syntax (although arguably,
407
+ this syntactic sugar could make it harder to spot). Moreover, having variables
408
+ with the same name in different scopes is broadly considered to be bad practice
409
+ and is discouraged by linters.
404
410
405
- Code editors could highlight the issue based on static analysis - ``f(x=) `` is
411
+ Code editors could highlight the issue based on static analysis -- ``f(x=) `` is
406
412
exactly equivalent to writing ``f(x=x) ``. If ``x `` does not exist, modern
407
413
editors have no problem highlighting the issue.
408
414
@@ -411,28 +417,28 @@ This syntax increases coupling
411
417
412
418
We recognise that, as ever, all syntax has the potential for misuse and so
413
419
should be applied judiciously to improve codebases. In this case, if a parameter
414
- and its value have the same semantics in both contexts, that may suggest that
415
- using this new syntax is appropriate and will help ameliorate the risk of
416
- unintentional desynchronisation which harms readability.
420
+ and its value have the same semantics in both contexts, that suggests that using
421
+ this syntax is appropriate and will help ameliorate the risk of unintentional
422
+ desynchronisation which harms readability.
417
423
418
- However, if the two variables have different semantics, that may suggest that
419
- this feature should not be used to encourage consistency or even that they
420
- should be renamed.
424
+ However, if the two variables have different semantics, that suggests that this
425
+ feature should not be used (since it encourages consistency) or perhaps that one
426
+ or both of the variables should be renamed.
421
427
422
- Recommendations for using this syntax
428
+ Recommendations for Using This Syntax
423
429
=====================================
424
430
425
431
As with any other language feature, the programmer should exercise their own
426
432
judgement about whether it is prudent to use it in any given context. We do not
427
433
recommend enforcing a rule to use the feature in all cases where it may be
428
- applicable.
434
+ applicable, such as via lint rules or style guides .
429
435
430
- As described ` above < This syntax increases coupling >`__ , we propose that a
431
- reasonable rule of thumb would be to use this in cases where a parameter and its
432
- argument have the same semantics in order to reduce unintentional
433
- desynchronisation without causing inappropriate coupling.
436
+ As described in ` This syntax increases coupling `_ , we propose that a reasonable
437
+ rule of thumb would be to use this in cases where a parameter and its argument
438
+ have the same semantics in order to reduce unintentional desynchronisation
439
+ without causing inappropriate coupling.
434
440
435
- Impact on editing
441
+ Impact on Editing
436
442
=================
437
443
438
444
Using a plain text editor
@@ -442,23 +448,23 @@ Editing with a plain text editor should generally be unaffected.
442
448
443
449
When renaming a variable using a 'Find-Replace' method, where this syntax is
444
450
used the developer will come across the function argument at invocation (as they
445
- would if this syntax was not used). At that point, they can as usual decide
451
+ would if this syntax was not used). At that point, they can, as usual, decide
446
452
whether to update the argument as well or expand to the full ``f(x=x) `` syntax.
447
453
448
454
As with the current syntax, a 'Find-Replace All' method would fail since the
449
455
keyword argument would not exist at function definition, in the vast majority
450
456
of cases.
451
457
452
458
If the developer leaves the argument name unchanged and forgets to update its
453
- value, a ``NameError `` will typically be raised as described
454
- `above < Renaming the variable in the calling context will break the code >`__ .
459
+ value, a ``NameError `` will typically be raised as described in
460
+ `Renaming the variable in the calling context will break the code `_ .
455
461
456
462
Proposals for IDEs
457
463
------------------
458
464
459
465
In response to community feedback, we include some suggestions regarding how
460
- IDEs could handle this syntax. However, we of course defer to the domain experts
461
- developing IDEs to use their own discretion.
466
+ IDEs could handle this syntax. However, we defer to the domain experts
467
+ developing IDEs to use their discretion.
462
468
463
469
Most considerations are made simple by recognising that ``f(x=) `` is just
464
470
syntactic sugar for ``f(x=x) `` and should be treated the same as at present.
@@ -468,9 +474,9 @@ Highlighting NameErrors
468
474
469
475
IDEs typically offer a feature to highlight code that may cause a ``NameError ``.
470
476
We recommend that this syntax be treated similarly to the expanded form
471
- ``f(x=x) `` to identify and highlight cases where the elided value variable may
472
- not exist. What visual cue may be used to highlight these cases may be the same
473
- or different from that which would be used with the current syntax, depending on
477
+ ``f(x=x) `` to identify and highlight cases where the elided variable may not
478
+ exist. What visual cue may be used to highlight these cases may be the same or
479
+ different from that which would be used with the current syntax, depending on
474
480
the IDE.
475
481
476
482
Jump to definition
@@ -510,18 +516,20 @@ this syntax. For example, if the argument is being renamed, the IDE may:
510
516
511
517
* Also rename the variable used as its value in each calling context where this
512
518
syntax is used
513
- * Expand to use the full syntax to pass the variable used as its value
519
+ * Expand to use the full syntax to pass the unchanged variable as the value of
520
+ the renamed argument
514
521
* Prompt the developer to select between the two above options
515
522
516
- The last option here seems most preferable in order to reduce unintentional
517
- desynchronisation of names while highlighting the user to the changes .
523
+ The last option seems to be the most preferable to reduce unintentional
524
+ desynchronisation of names while highlighting the changes to the programmer .
518
525
519
526
Reference Implementation
520
527
========================
521
528
522
529
`A proposed implementation <https://github.com/Hels15/cpython/tree/last-build >`_
523
- for cpython has been provided by @Hels15. We will extend this implementation to
530
+ for CPython has been provided by @Hels15. We will extend this implementation to
524
531
add an AST node attribute indicating for keywords whether the value was elided.
532
+ Otherwise the AST will remain unchanged.
525
533
526
534
References
527
535
==========
0 commit comments