Apply Mark's latest changes to PEP 505

This commit is contained in:
Chris Angelico 2015-10-28 03:59:43 +11:00
parent 0bc5287a60
commit 23a9ad5cc1
1 changed files with 47 additions and 34 deletions

View File

@ -229,12 +229,16 @@ For inexperienced developers, the problem is worse. The top Google hit for
<http://stackoverflow.com/questions/4978738/is-there-a-python-equivalent-of- <http://stackoverflow.com/questions/4978738/is-there-a-python-equivalent-of-
the-c-sharp-null-coalescing-operator>`_, and the top answer says to use ``or``. the-c-sharp-null-coalescing-operator>`_, and the top answer says to use ``or``.
The top answer goes on to explain the caveats of using ``or`` like this, but how The top answer goes on to explain the caveats of using ``or`` like this, but how
many beginning developers go on to read all those caveats? many beginning developers go on to read all those caveats? The accepted answer
on `a more recent question <http://stackoverflow.com/questions/13710631/is-
there-shorthand-for-returning-a -default-value-if-none-in-python>`_ says to use
``or`` without any caveats at all. These two questions have a combined 26,000
views!
The common usage of ``or`` for the purpose of providing default values is The common usage of ``or`` for the purpose of providing default values is
undeniable, and yet it is also booby-trapped for unsuspecting newcomers. This undeniable, and yet it is also booby-trapped for unsuspecting newcomers. This
suggests that a safe operator for providing default values would have positive suggests that a safe operator for providing default values would have positive
utility. While some critics claim that ``None-aware`` operators will be abused utility. While some critics claim that ``None``-aware operators will be abused
for error handling, they are no more prone to abuse than ``or`` is. for error handling, they are no more prone to abuse than ``or`` is.
@ -773,36 +777,44 @@ Note in the last example that ``time.sleep(10)`` represents an expensive
function call, e.g. initializing a complex data structure. In this example function call, e.g. initializing a complex data structure. In this example
``time.sleep`` is not evaluated, and the result ``300`` is returned instantly. ``time.sleep`` is not evaluated, and the result ``300`` is returned instantly.
The operator has precedence lower than ``not`` but higher than ``and`` and The operator has higher precedence than the comparison operators ``==``, ``>``,
``or``. This precedence makes reasoning about the order of operations ``is``, etc., but lower precedence than any bitwise or arithmetic operators.
comfortable, because it has precedence similar to the operators used for This precedence is chosen for making "default value" expressions intuitive to
coalescing false-y values. Here are pairs of examples, where each item in the read and write::
pair is evaluated identically to the other item in the pair::
>>> not None ✊🍆 False >>> user_flag = None
True >>> default_flag = True
>>> (not None) ✊🍆 False >>> not user_flag ✊🍆 default_flag # Same as next expression.
False
>>> not (user_flag ✊🍆 default_flag) # Same as previous.
False
>>> (not user_flag) ✊🍆 default_flag # Different from previous.
True True
>>> 'foo' in dict() ✊🍆 {'foo': 'bar'} >>> user_quantity = None
False >>> default_quantity = 1
>>> ('foo' in dict()) ✊🍆 {'foo': 'bar'} >>> 1 == user_quantity ✊🍆 default_quantity # Same as next expression.
True
>>> 1 == (user_quantity ✊🍆 default_quantity) # Same as previous.
True
>>> (1 == user_quantity) ✊🍆 default_quantity # Different from previous.
False False
>>> 1 == None ✊🍆 1 >>> user_words = None
False >>> default_words = ['foo', 'bar']
>>> (1 == None) ✊🍆 1 >>> 'foo' in user_words ✊🍆 default_words # Same as next expression.
False True
>>> 'foo' in (user_words ✊🍆 default_words) # Same as previous.
But ``and`` and ``or`` have lower precedence:: True
>>> ('foo' in user_words) ✊🍆 default_words # Different from previous.
>>> 2 or None ✊🍆 err()
Traceback (most recent call last): Traceback (most recent call last):
File "<stdin>", line 1, in <module> File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in err TypeError: argument of type 'NoneType' is not iterable
Exception: foo
>>> (2 or None) ✊🍆 err() >>> user_discount = None
2 >>> default_discount = 0.9
>>> price = 100
>>> price * user_discount ✊🍆 default_discount
Recall the example above of calculating the cost of items in a shopping cart, Recall the example above of calculating the cost of items in a shopping cart,
and the easy-to-miss bug. This type of bug is not possible with the ``None``- and the easy-to-miss bug. This type of bug is not possible with the ``None``-
@ -840,9 +852,8 @@ preserving the short circuit semantics of the code that it replaces.
-------------------------- --------------------------
The idea of a ``None``-aware function invocation syntax was discussed on python- The idea of a ``None``-aware function invocation syntax was discussed on python-
ideas, but the idea was rejected by BDFL. The reasons for this rejection are ideas. The idea was not popular, so no such operator is included in this
detailed above. proposal. (Justification for its exclusion is discussed in a previous section.)
Still, calling a function when it is not ``None`` is a common idiom in Python, Still, calling a function when it is not ``None`` is a common idiom in Python,
particularly for callback functions. Consider this hypothetical example:: particularly for callback functions. Consider this hypothetical example::
@ -865,10 +876,11 @@ written more concisely as::
Instead, consider a "``None``-severing" operator, however, which is a short- Instead, consider a "``None``-severing" operator, however, which is a short-
circuiting, boolean operator similar to the ``None``-coalesing operator, except circuiting, boolean operator similar to the ``None``-coalesing operator, except
it returns its left operand if that operand is None and otherwise returns the it returns ``None`` if the left operand is ``None`` and returns the right
right operand. If the left operand is None, then the right operand is not operand otherwise. It has short circuiting behavior that compliments the
evaluated. Let's temporarily spell this operator ``✂`` and rewrite the example ``None``-coalescing operator: if the left operand is None, then the right
accordingly:: operand is not evaluated. Let's temporarily spell this operator ``✂`` and
rewrite the example accordingly::
import time import time
@ -1153,7 +1165,7 @@ operator.
2. ``foo or? bar or? baz`` 2. ``foo or? bar or? baz``
- Pros: similar to existing ``or`` operator - Pros: similar to existing ``or`` operator
- Cons: the difference between this and ``or`` is not intuitive; punctuation - Cons: the difference between this and ``or`` is not intuitive; punctuation
is ugly is ugly; different precedence from ``or`` may be confusing
3. ``foo ? bar ? baz`` 3. ``foo ? bar ? baz``
- Pros: similar to ``??`` used in other languages - Pros: similar to ``??`` used in other languages
- Cons: punctuation is ugly; possible conflict with IPython; not used by any - Cons: punctuation is ugly; possible conflict with IPython; not used by any
@ -1189,7 +1201,8 @@ the ``None``- coalescing operator.
2. ``foo and? bar`` 2. ``foo and? bar``
- Pros: symmetric with ``or?`` - Pros: symmetric with ``or?``
- Cons: punctuation is ugly; possible conflict with IPython; difficult to - Cons: punctuation is ugly; possible conflict with IPython; difficult to
google to find out what it means google to find out what it means; different precedence from ``and`` may be
confusing
3. No ``None``-severing operator. 3. No ``None``-severing operator.
- (Pros and cons discussed throughout this document.) - (Pros and cons discussed throughout this document.)