Skip to content

Commit 3d0b0a1

Browse files
committed
Minor changes
1 parent ca34522 commit 3d0b0a1

1 file changed

Lines changed: 31 additions & 25 deletions

File tree

peps/pep-0999.rst

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ This PEP proposes adding two new operators.
1919
* The "``None``-aware indexing" operator ``?[ ]`` ("maybe subscript")
2020

2121
Both operators evaluate the left hand side, check if it is not ``None``
22-
and only then evaluate the full expression. They are roughly equal to::
22+
and only then evaluate the full expression. They are roughly equivalent
23+
to:
24+
25+
.. code-block:: python
2326
2427
# a.b?.c
2528
_t1.c if ((_t1 := a.b) is not None) else None
@@ -80,7 +83,7 @@ modern programming languages have so called "``null``-aware" or
8083
ECMAScript (a.k.a. JavaScript) [#js]_, C# [#csharp]_, Dart [#dart]_,
8184
Swift [#swift]_, Kotlin [#kotlin]_, Ruby [#ruby]_, PHP [#php]_ and more.
8285

83-
The general idea is to provide a access operators which can traverse
86+
The general idea is to provide access operators which can traverse
8487
``null`` or ``None`` values without raising exceptions.
8588

8689
Nested objects with ``optional`` attributes
@@ -89,7 +92,7 @@ Nested objects with ``optional`` attributes
8992
When writing Python code, it is common to encounter objects with ``optional``
9093
attributes. Accessing attributes, subscript or function calls can raise
9194
``AttributeError`` or ``IndexError`` at runtime if the value is ``None``.
92-
Several common patterns have developed to ensure those operators are will
95+
Several common patterns have developed to ensure these operations will
9396
not raise. The goal for ``?.`` and ``?[ ]`` is to make reading and writing
9497
these expressions much simpler while being predictable and doing the
9598
correct things intuitively.
@@ -171,11 +174,11 @@ Writing it like this is correct but, especially for deeply nested
171174
object hierarchies, difficult to read and easy to get wrong.
172175

173176
Alternative approaches include wrapping the whole expression with
174-
a try-except block. While this would also archive the desired
177+
a try-except block. While this would also achieve the desired
175178
output, it as well has the potential to introduce errors which
176-
might get unnoticed. E.g. if the ``Line.department`` gets deprecated,
177-
in the process making it ``optional`` and always return ``None``, the
178-
function would still succeed, even though the input changed significantly.
179+
might get unnoticed. E.g. if the ``Line.department`` attribute gets deprecated, in the process making it ``optional`` and always return
180+
``None``, the function would still succeed, even though the input changed
181+
significantly.
179182

180183
.. code-block:: python
181184
@@ -186,7 +189,7 @@ function would still succeed, even though the input changed significantly.
186189
return None
187190
188191
Another approach would be to use a ``match`` statement instead. This
189-
will work fine but is easy to get wrong as well. It's strongly
192+
will work fine but is easy to get wrong as well. It is strongly
190193
recommended to use keyword attributes as otherwise any change in
191194
``__match_args__`` would cause the pattern match to fail.
192195
If any attribute names change, the match statement needs to be
@@ -225,8 +228,9 @@ To start, assume each attribute, subscript and function call is
225228
return sensor.machine.line.department.engineer.email[0]
226229
227230
Now insert ``?`` after each ``optional`` subexpression. IDEs and most
228-
type checkers would be able to help with that since the data structure
229-
is strictly typed. *Spaces added for clarity only, though still valid*::
231+
type checkers would often be able to help with that especially if the
232+
data structure is strictly typed. *Spaces added for clarity only,
233+
though still valid*::
230234

231235
def get_person_email(sensor: Sensor) -> str | None:
232236
return sensor.machine? .line? .department.engineer? .email? [0]
@@ -259,8 +263,8 @@ Parsing structured data
259263

260264
The ``?.`` and ``?[ ]`` operators can also aid in the traversal of
261265
structured data, oftentimes coming from JSON and parsed as nested
262-
dicts and lists. It is worth noting though that they do not handle
263-
``missing`` attributes / data. For dictionaries a useful helper is
266+
dicts and lists. It is worth noting though that the operators do not
267+
handle ``missing`` attributes / data. For dictionaries a useful helper is
264268
the ``.get(key, default=None)`` method with a default. Depending on
265269
the specific use case, pattern matching might also be a viable
266270
alternative here.
@@ -408,7 +412,9 @@ access were used.
408412
_t.c() if ((_t := a.b) is not None) else None
409413

410414
# a?.b?.c.d
411-
_t2.c.d if ((_t1 := a) is not None) and ((_t2 := t1.b) is not None) else None
415+
_t2.c.d if (
416+
(_t2 := _t1.b if ((_t1 := a) is not None) else None) is not None
417+
) else None
412418

413419
Short-circuiting
414420
****************
@@ -501,7 +507,7 @@ AST changes
501507
Two new AST nodes are added ``NoneAwareAttribute`` and ``NoneAwareSubscript``.
502508
They are the counterparts to the existing ``Attribute`` and ``Subscript``
503509
nodes. Notably there is no ``expr_context`` attribute because the new nodes
504-
do not support assignments itself and thus the context will always be
510+
do not support assignments themselves and thus the context will always be
505511
``Load``.
506512

507513
::
@@ -539,7 +545,7 @@ Multiline formatting
539545

540546
Using two separate tokens to express ``?.`` and ``?[`` allows developers
541547
to insert a space or line break as needed. For multiline expressions it
542-
allows that ``?`` is appended to the ``optional`` subexpression whereas
548+
enables that ``?`` is appended to the ``optional`` subexpression whereas
543549
``.`` or ``[`` could be moved to the next line. This is indented merely
544550
as an option for developers. Everyone is free to choose a style that fits
545551
their needs, especially code formatters might prefer a style which
@@ -674,7 +680,7 @@ added for attribute and item access automatically.
674680

675681
While this might be easier to write at first, it introduces new issues.
676682
When using explicit ``?.`` and ``?[ ]`` operators, the input space is well
677-
defined. Only ``a``, ``.c`` and ``d`` are expected to possibly be ``None``.
683+
defined. Only ``a``, ``.c`` and ``.d`` are expected to possibly be ``None``.
678684
If ``.b`` all of the sudden is also ``None``, it would still raise an
679685
``AttributeError`` since it was unexpected. That would not happen for
680686
``maybe``. This behavior is problematic since it can subtly hide real
@@ -696,8 +702,8 @@ operators introduced, a unary, postfix operator ``?`` was considered.
696702

697703
While this might have made teaching the operators a bit easier, just one
698704
instead of two new operators, it may also be **too general**, in a sense
699-
that it can be combine with any other operator. It is not clear what the
700-
following expressions would mean::
705+
that it can be combine with any other operator. For example it is not
706+
clear what the following expressions would mean::
701707

702708
>>> x? + 1
703709
>>> x? -= 1
@@ -728,7 +734,7 @@ There are a number of libraries which provide some kind of object
728734
traversal functions. The most popular likely being ``glom`` [#glom]_.
729735
Others include ``jmespath`` [#jmespath]_ and ``nonesafe`` [#nonesafe]_.
730736
The idea is usually to pass an object and the lookup attributes as
731-
string to a function which handles the rest.
737+
string to a function which handles the evaluation.
732738

733739
.. code-block:: python
734740
@@ -744,7 +750,7 @@ It was suggested to add a ``traverse`` or ``deepget`` function to the
744750
stdlib. While these libraries do work and have its use cases, especially
745751
``glom`` provides an excellent interface to extract and combine multiple
746752
data points from deeply nested objects, they do also have some
747-
disadvantages. Passing the lookup attributes as string means that often
753+
disadvantages. Passing the lookup attributes as a string means that often
748754
times there are no more IDE suggestions. Type checking these expressions
749755
is also limited. Furthermore, normal function calls can not provide
750756
short-circuiting, so they would still need to be combined with assignment
@@ -839,11 +845,11 @@ either ``?.`` (or ``?:``). Using anything else would be unexpected.
839845
Defer ``None``-aware indexing operator
840846
--------------------------------------
841847

842-
A point of discussion was the ``?[ ]`` operator. Some though it might be
848+
A point of discussion was the ``?[ ]`` operator. Some thought it might be
843849
missed to easily in an expression ``a.b?[c]``. To move the discussion
844-
forward, some suggested to defer the operator for later.
850+
forward, it was suggested to defer the operator for later.
845851

846-
While it is often helpful to reduce the scope to move forward at all,
852+
Though it is often helpful to reduce the scope to move forward at all,
847853
the ``?[ ]`` operator is necessary to efficiently get items from
848854
``optional`` objects. While for dictionary a suitable alternative is to
849855
use ``d?.get(key)``, for general objects developers would have needed
@@ -939,15 +945,15 @@ As shown in the `Motivation`_ section, the operators are not designed
939945
to handle arbitrary data, rather to make it easier to work with nested
940946
objects with ``optional`` attributes. If arbitrary data handling is the
941947
goal, other language concepts are likely better suited, like try-except,
942-
a match statement or different data traversal libraries from PyPI.
948+
a match statement or data traversal libraries from PyPI.
943949

944950
See the `Exception-aware operators`_ section for more details why
945951
this was rejected.
946952

947953
Just use ...
948954
------------
949955

950-
A comment reply towards the proposal was to use an existing language
956+
A common reply towards the proposal was to use an existing language
951957
concept instead of introducing a syntax. A few alternatives have been
952958
proposed.
953959

0 commit comments

Comments
 (0)