Skip to content

Commit afb44de

Browse files
committed
Additional improvements
1 parent ee31e29 commit afb44de

File tree

1 file changed

+34
-24
lines changed

1 file changed

+34
-24
lines changed

peps/pep-0999.rst

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ An attribute or value is ``optional``
3939
In the context of this PEP an attribute or value is considered
4040
``optional`` if it is always present but can be ``None``.
4141

42-
.. code-block:: python
42+
.. code-block:: python-console
4343
4444
>>> class A:
4545
... def __init__(self, val: int | None) -> None:
@@ -54,7 +54,7 @@ An attribute or value is ``missing``
5454
at all. For ``typing.TypedDict`` these would be ``typing.NotRequired``
5555
keys when they are not preset.
5656

57-
.. code-block:: python
57+
.. code-block:: python-console
5858
5959
>>> class A:
6060
... val: int | None
@@ -240,13 +240,17 @@ To start, assume each attribute, subscript and function call is
240240
241241
Now insert ``?`` after each ``optional`` subexpression. IDEs and most
242242
type checkers will be able to help with identifying these. *Spaces added
243-
for clarity only, though still valid*::
243+
for clarity only, though still valid*:
244+
245+
::
244246

245247
def get_person_email(sensor: Sensor) -> str | None:
246248
return sensor.machine? .line? .department.engineer? .email? [0]
247249
# ^^^^^^^^ ^^^^^ ^^^^^^^^^ ^^^^^^
248250

249-
The complete function would then be::
251+
The complete function would then be:
252+
253+
::
250254

251255
def get_person_email(sensor: Sensor) -> str | None:
252256
return sensor.machine?.line?.department.engineer?.email?[0]
@@ -588,7 +592,9 @@ Grammar changes
588592
---------------
589593

590594
A new ``?`` token is added. In addition the ``primary`` grammar rule is
591-
updated to include ``none_aware_attribute`` and ``none_aware_subscript``::
595+
updated to include ``none_aware_attribute`` and ``none_aware_subscript``.
596+
597+
.. code-block:: PEG
592598
593599
primary:
594600
| primary '.' NAME
@@ -751,8 +757,8 @@ defined. Only ``a``, ``.c`` and ``.d`` are expected to possibly be ``None``.
751757
If ``.b`` all of the sudden is also ``None``, it would still raise an
752758
``AttributeError`` since it was unexpected. That would not happen for
753759
``maybe``. This behavior is problematic since it can subtly hide real
754-
issues. As the expression output can already be ``None`` the space of
755-
potential output didn't change and as such no error would appear.
760+
issues. As the expression output can already be ``None``, the space of
761+
potential outputs didn't change and as such no error would appear.
756762

757763
If it is the intend to catch all ``AttributeError`` and ``TypeError``,
758764
a try-except block can be used instead.
@@ -797,7 +803,9 @@ operators introduced, a unary, postfix operator ``?`` was considered.
797803
While this might have made teaching the operators a bit easier, just one
798804
instead of two new operators, it may also be **too general**, in a sense
799805
that it can be combine with any other operator. For example it is not
800-
clear what the following expressions would mean::
806+
clear what the following expressions would mean:
807+
808+
::
801809

802810
>>> x? + 1
803811
>>> x? -= 1
@@ -819,7 +827,7 @@ values in nested objects with ``optional`` attributes.
819827

820828
If future PEPs want to introduce new operators to access attributes or
821829
call methods, e.g. a chaining operator, it would be advisable to consider
822-
if a ``None``-aware variant for it could be useful at that time.
830+
if a ``None``-aware variant for it could be useful, at that time.
823831

824832
Builtin function for traversal
825833
------------------------------
@@ -828,9 +836,10 @@ There are a number of libraries which provide some kind of object
828836
traversal functions. The most popular likely being ``glom`` [#glom]_.
829837
Others include ``jmespath`` [#jmespath]_ and ``nonesafe`` [#nonesafe]_.
830838
The idea is usually to pass an object and the lookup attributes as
831-
string to a function which handles the evaluation.
839+
string to a function which handles the evaluation. It was suggested
840+
to add a ``traverse`` or ``deepget`` function to the stdlib.
832841

833-
.. code-block:: python
842+
.. code-block:: python-console
834843
835844
# pip install glom
836845
>>> from glom import glom
@@ -840,8 +849,7 @@ string to a function which handles the evaluation.
840849
>>> glom(data, "a.b.f.g", default=2)
841850
2
842851
843-
It was suggested to add a ``traverse`` or ``deepget`` function to the
844-
stdlib. While these libraries do work and have its use cases, especially
852+
While these libraries do work and have its use cases, especially
845853
``glom`` provides an excellent interface to extract and combine multiple
846854
data points from deeply nested objects, they do also have some
847855
disadvantages. Passing the lookup attributes as a string means that often
@@ -859,7 +867,9 @@ either an instance of ``Something`` or an instance of ``Nothing``.
859867
on ``optional`` attributes.
860868

861869
A Python package called ``pymaybe`` [#pymaybe]_ provides a rough
862-
approximation. An example could look like this::
870+
approximation. An example could look like this:
871+
872+
.. code-block:: python-console
863873
864874
# pip install pymaybe
865875
>>> from pymaybe import maybe
@@ -900,8 +910,8 @@ expressions need to be written and evaluated today.
900910

901911
An advantages of the ``?.`` and ``?[ ]`` operators is that they do not
902912
change the result much aside from adding ``None`` as a possible return
903-
of an expression. As such they are a better solution for the use cases
904-
outlined in the `Motivation`_ section.
913+
value of an expression. As such they are a better solution for the use
914+
cases outlined in the `Motivation`_ section.
905915

906916
No-Value Protocol
907917
-----------------
@@ -918,7 +928,7 @@ replaced with ``x.__has_value__()``.
918928
There are a few obvious candidates like ``math.nan`` and ``NotImplemented``.
919929
However, while these could be interpreted as representing no value, the
920930
interpretation is **domain specific**. For the language itself they *should*
921-
be treated as values. For example ``math.nan.imag`` is well defined
931+
still be treated as values. For example ``math.nan.imag`` is well defined
922932
(it is ``0.0``) and so short-circuiting ``math.nan?.imag`` to return
923933
``None`` would be incorrect.
924934

@@ -935,8 +945,8 @@ Though possible, the ``->`` operator is already used in Python for
935945
something completely different. Additionally, a majority of other
936946
languages which support "``null``-aware" or "optional chaining"
937947
operators use ``?.``. Some exceptions being Ruby [#ruby]_ with ``&.``
938-
or PHP [#php]_ with ``?->``. The ``?`` does not have an assigned
939-
meaning in Python just yet. As such it makes sense to adopt
948+
or PHP [#php]_ with ``?->``. The ``?`` character does not have an
949+
assigned meaning in Python just yet. As such it makes sense to adopt
940950
the most common spelling for the ``None``-aware access operators.
941951
Especially considering that it also works well with the "normal"
942952
``.`` and ``[ ]`` operators.
@@ -950,7 +960,7 @@ forward, it was suggested to defer the operator for later.
950960

951961
Though it is often helpful to reduce the scope to move forward at all,
952962
the ``?[ ]`` operator is necessary to efficiently get items from
953-
``optional`` objects. While for dictionary a suitable alternative is to
963+
``optional`` objects. While for dictionaries a suitable alternative is to
954964
use ``d?.get(key)``, for general objects developers would have needed
955965
to defer to ``o?.__getitem__(key)``.
956966

@@ -1043,7 +1053,7 @@ Difficult to read
10431053
-----------------
10441054

10451055
A common objection raised during the discussion was that ``None``-aware
1046-
operators are difficult to read in expressions and add line noise. It
1056+
operators are difficult to read in expressions and add line noise. They
10471057
might be too easy to miss besides "normal" attribute access and subscript
10481058
operators.
10491059

@@ -1127,7 +1137,7 @@ Some have pointed the `Short-circuiting`_ behavior might be difficult
11271137
to understand and suggested to remove it in favor of a simplified
11281138
proposal.
11291139

1130-
It is true that using short-circuiting that way is new to Python and
1140+
It is true that using short-circuiting that way is uncommon in Python and
11311141
as such unknown. That closest analogs would be boolean expressions like
11321142
``a or b``, ``a and b`` which do also short-circuit the expression if
11331143
the first value is truthy or falsy respectively. However, while
@@ -1156,8 +1166,8 @@ Just use ...
11561166
------------
11571167

11581168
A common reply towards the proposal was to use an existing language
1159-
concept instead of introducing a syntax. A few alternatives have been
1160-
proposed.
1169+
concept instead of introducing a new syntax. A few alternatives have
1170+
been proposed.
11611171

11621172
... a conditional expression
11631173
****************************

0 commit comments

Comments
 (0)